From 2972cf506d4fe94ad265d198b30fa666ea7b40c6 Mon Sep 17 00:00:00 2001 From: Blake Burkhart Date: Wed, 7 Jan 2015 22:11:31 -0600 Subject: [PATCH] Optionally allow unregistered users to view challenges Add a Config entry `view_challenges_unregistered` to indicate whether unregistered users can view challenges. Add the setting to the admin config page. Add can_view_challenges() to utils to test if a user is either authed, or the configuration allow unauthenticated users to view the challenges. Return a HTTP 401 Unauthorized error when the /chals/solves API can't provide results for an unauthenticated user. This is needed because the client side code in `chalboard.js` doesn't know if it's logged in or not and requests this anyway. (And AJAX doesn't handle redirects very well.) Alternately the client could actually know if they're logged in and not make needless API calls. When an unregistered user attempts to submit a flag, it will also fail. The user will be redirected to a login page. --- CTFd/admin.py | 14 ++++++++++++-- CTFd/challenges.py | 10 +++++----- CTFd/utils.py | 3 +++ CTFd/views.py | 4 ++++ templates/admin/config.html | 18 ++++++++++++++---- 5 files changed, 38 insertions(+), 11 deletions(-) diff --git a/CTFd/admin.py b/CTFd/admin.py index d4709a6..1a3acbe 100644 --- a/CTFd/admin.py +++ b/CTFd/admin.py @@ -52,7 +52,12 @@ def init_admin(app): start = None end = None - print repr(start), repr(end) + try: + view_challenges_unregistered = bool(request.form.get('view_challenges_unregistered', None)) + except (ValueError, TypeError): + view_challenges_unregistered = None + + print repr(start), repr(end), repr(view_challenges_unregistered) db_start = Config.query.filter_by(key='start').first() db_start.value = start @@ -60,14 +65,19 @@ def init_admin(app): db_end = Config.query.filter_by(key='end').first() db_end.value = end + db_view_challenges_unregistered = Config.query.filter_by(key='view_challenges_unregistered').first() + db_view_challenges_unregistered.value = view_challenges_unregistered + db.session.add(db_start) db.session.add(db_end) + db.session.add(db_view_challenges_unregistered) db.session.commit() return redirect('/admin/config') start = Config.query.filter_by(key="start").first().value end = Config.query.filter_by(key="end").first().value - return render_template('admin/config.html', start=start, end=end) + view_challenges_unregistered = (Config.query.filter_by(key='view_challenges_unregistered').first().value == '1') + return render_template('admin/config.html', start=start, end=end, view_challenges_unregistered=view_challenges_unregistered) @app.route('/admin/pages', defaults={'route': None}, methods=['GET', 'POST']) @app.route('/admin/pages/', methods=['GET', 'POST']) diff --git a/CTFd/challenges.py b/CTFd/challenges.py index c26a057..2767212 100644 --- a/CTFd/challenges.py +++ b/CTFd/challenges.py @@ -1,6 +1,6 @@ from flask import current_app as app, render_template, request, redirect, abort, jsonify, json as json_mod, url_for, session -from CTFd.utils import ctftime, authed, unix_time, get_kpm +from CTFd.utils import ctftime, authed, unix_time, get_kpm, can_view_challenges from CTFd.models import db, Challenges, Files, Solves, WrongKeys, Keys import time @@ -12,7 +12,7 @@ def init_challenges(app): def challenges(): if not ctftime(): return redirect('/') - if authed(): + if can_view_challenges(): return render_template('chals.html') else: return redirect(url_for('login', next="challenges")) @@ -21,7 +21,7 @@ def init_challenges(app): def chals(): if not ctftime(): return redirect('/') - if authed(): + if can_view_challenges(): chals = Challenges.query.add_columns('id', 'name', 'value', 'description', 'category').order_by(Challenges.value).all() json = {'game':[]} @@ -37,7 +37,7 @@ def init_challenges(app): @app.route('/chals/solves') def chals_per_solves(): - if authed(): + if can_view_challenges(): solves = Solves.query.add_columns(db.func.count(Solves.chalid)).group_by(Solves.chalid).all() json = {} for chal, count in solves: @@ -52,7 +52,7 @@ def init_challenges(app): if authed(): solves = Solves.query.filter_by(teamid=session['id']).all() else: - return redirect('/login') + abort(401) else: solves = Solves.query.filter_by(teamid=teamid).all() db.session.close() diff --git a/CTFd/utils.py b/CTFd/utils.py index 931a791..9f8cfdd 100644 --- a/CTFd/utils.py +++ b/CTFd/utils.py @@ -83,6 +83,9 @@ def ctftime(): return False +def can_view_challenges(): + return authed() or (Config.query.filter_by(key="view_challenges_unregistered").first().value == '1'); + def unix_time(dt): epoch = datetime.datetime.utcfromtimestamp(0) delta = dt - epoch diff --git a/CTFd/views.py b/CTFd/views.py index 4bf5368..8ffe89f 100644 --- a/CTFd/views.py +++ b/CTFd/views.py @@ -63,12 +63,16 @@ def init_views(app): start = Config('start', None) end = Config('end', None) + ## Challenges cannot be viewed by unregistered users + view_challenges_unregistered = Config('view_challenges_unregistered', None) + setup = Config('setup', True) db.session.add(admin) db.session.add(page) db.session.add(start) db.session.add(end) + db.session.add(view_challenges_unregistered) db.session.add(setup) db.session.commit() app.setup = False diff --git a/templates/admin/config.html b/templates/admin/config.html index 90dc193..bb81cc5 100644 --- a/templates/admin/config.html +++ b/templates/admin/config.html @@ -6,11 +6,21 @@

Config

- Start Date: - - End Date: - +
+ + +
+ +
+ + +
+ +
+ + +