mirror of
https://github.com/aljazceru/CTFd.git
synced 2025-12-17 14:04:20 +01:00
Plugins enhanced utils (#231)
* Updating utils functions to be monkey patchable * Also fixing a team email update issue * Adding more tests
This commit is contained in:
@@ -8,7 +8,8 @@ from sqlalchemy.exc import OperationalError, ProgrammingError
|
|||||||
from sqlalchemy_utils import database_exists, create_database
|
from sqlalchemy_utils import database_exists, create_database
|
||||||
from six.moves import input
|
from six.moves import input
|
||||||
|
|
||||||
from CTFd.utils import get_config, set_config, cache, migrate, migrate_upgrade, migrate_stamp
|
from CTFd.utils import cache, migrate, migrate_upgrade, migrate_stamp
|
||||||
|
from CTFd import utils
|
||||||
|
|
||||||
__version__ = '1.0.1'
|
__version__ = '1.0.1'
|
||||||
|
|
||||||
@@ -16,7 +17,7 @@ class ThemeLoader(FileSystemLoader):
|
|||||||
def get_source(self, environment, template):
|
def get_source(self, environment, template):
|
||||||
if template.startswith('admin/'):
|
if template.startswith('admin/'):
|
||||||
return super(ThemeLoader, self).get_source(environment, template)
|
return super(ThemeLoader, self).get_source(environment, template)
|
||||||
theme = get_config('ctf_theme')
|
theme = utils.get_config('ctf_theme')
|
||||||
template = "/".join([theme, template])
|
template = "/".join([theme, template])
|
||||||
return super(ThemeLoader, self).get_source(environment, template)
|
return super(ThemeLoader, self).get_source(environment, template)
|
||||||
|
|
||||||
@@ -53,10 +54,10 @@ def create_app(config='CTFd.config.Config'):
|
|||||||
cache.init_app(app)
|
cache.init_app(app)
|
||||||
app.cache = cache
|
app.cache = cache
|
||||||
|
|
||||||
version = get_config('ctf_version')
|
version = utils.get_config('ctf_version')
|
||||||
|
|
||||||
if not version: ## Upgrading from an unversioned CTFd
|
if not version: ## Upgrading from an unversioned CTFd
|
||||||
set_config('ctf_version', __version__)
|
utils.set_config('ctf_version', __version__)
|
||||||
|
|
||||||
if version and (StrictVersion(version) < StrictVersion(__version__)): ## Upgrading from an older version of CTFd
|
if version and (StrictVersion(version) < StrictVersion(__version__)): ## Upgrading from an older version of CTFd
|
||||||
print("/*\\ CTFd has updated and must update the database! /*\\")
|
print("/*\\ CTFd has updated and must update the database! /*\\")
|
||||||
@@ -65,13 +66,13 @@ def create_app(config='CTFd.config.Config'):
|
|||||||
if input('Run database migrations (Y/N)').lower().strip() == 'y':
|
if input('Run database migrations (Y/N)').lower().strip() == 'y':
|
||||||
migrate_stamp()
|
migrate_stamp()
|
||||||
migrate_upgrade()
|
migrate_upgrade()
|
||||||
set_config('ctf_version', __version__)
|
utils.set_config('ctf_version', __version__)
|
||||||
else:
|
else:
|
||||||
print('/*\\ Ignored database migrations... /*\\')
|
print('/*\\ Ignored database migrations... /*\\')
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
if not get_config('ctf_theme'):
|
if not utils.get_config('ctf_theme'):
|
||||||
set_config('ctf_theme', 'original')
|
utils.set_config('ctf_theme', 'original')
|
||||||
|
|
||||||
from CTFd.views import views
|
from CTFd.views import views
|
||||||
from CTFd.challenges import challenges
|
from CTFd.challenges import challenges
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ from flask import current_app as app, render_template, request, redirect, jsonif
|
|||||||
from passlib.hash import bcrypt_sha256
|
from passlib.hash import bcrypt_sha256
|
||||||
from sqlalchemy.sql import not_
|
from sqlalchemy.sql import not_
|
||||||
|
|
||||||
from CTFd.utils import admins_only, is_admin, unix_time, get_config, \
|
from CTFd.utils import admins_only, is_admin, cache
|
||||||
set_config, sendmail, rmdir, create_image, delete_image, run_image, container_status, container_ports, \
|
|
||||||
container_stop, container_start, get_themes, cache, upload_file, get_configurable_plugins
|
|
||||||
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
||||||
from CTFd.scoreboard import get_standings
|
from CTFd.scoreboard import get_standings
|
||||||
from CTFd.plugins.keys import get_key_class, KEY_CLASSES
|
from CTFd.plugins.keys import get_key_class, KEY_CLASSES
|
||||||
@@ -22,6 +20,8 @@ from CTFd.admin.containers import admin_containers
|
|||||||
from CTFd.admin.keys import admin_keys
|
from CTFd.admin.keys import admin_keys
|
||||||
from CTFd.admin.teams import admin_teams
|
from CTFd.admin.teams import admin_teams
|
||||||
|
|
||||||
|
from CTFd import utils
|
||||||
|
|
||||||
|
|
||||||
admin = Blueprint('admin', __name__)
|
admin = Blueprint('admin', __name__)
|
||||||
|
|
||||||
@@ -38,13 +38,13 @@ def admin_view():
|
|||||||
@admins_only
|
@admins_only
|
||||||
def admin_plugin_config(plugin):
|
def admin_plugin_config(plugin):
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
if plugin in get_configurable_plugins():
|
if plugin in utils.get_configurable_plugins():
|
||||||
config = open(os.path.join(app.root_path, 'plugins', plugin, 'config.html')).read()
|
config = open(os.path.join(app.root_path, 'plugins', plugin, 'config.html')).read()
|
||||||
return render_template('admin/page.html', content=config)
|
return render_template('admin/page.html', content=config)
|
||||||
abort(404)
|
abort(404)
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
for k, v in request.form.items():
|
for k, v in request.form.items():
|
||||||
set_config(k, v)
|
utils.set_config(k, v)
|
||||||
return '1'
|
return '1'
|
||||||
|
|
||||||
|
|
||||||
@@ -80,28 +80,28 @@ def admin_config():
|
|||||||
mail_tls = None
|
mail_tls = None
|
||||||
mail_ssl = None
|
mail_ssl = None
|
||||||
finally:
|
finally:
|
||||||
view_challenges_unregistered = set_config('view_challenges_unregistered', view_challenges_unregistered)
|
view_challenges_unregistered = utils.set_config('view_challenges_unregistered', view_challenges_unregistered)
|
||||||
view_scoreboard_if_authed = set_config('view_scoreboard_if_authed', view_scoreboard_if_authed)
|
view_scoreboard_if_authed = utils.set_config('view_scoreboard_if_authed', view_scoreboard_if_authed)
|
||||||
hide_scores = set_config('hide_scores', hide_scores)
|
hide_scores = utils.set_config('hide_scores', hide_scores)
|
||||||
prevent_registration = set_config('prevent_registration', prevent_registration)
|
prevent_registration = utils.set_config('prevent_registration', prevent_registration)
|
||||||
prevent_name_change = set_config('prevent_name_change', prevent_name_change)
|
prevent_name_change = utils.set_config('prevent_name_change', prevent_name_change)
|
||||||
view_after_ctf = set_config('view_after_ctf', view_after_ctf)
|
view_after_ctf = utils.set_config('view_after_ctf', view_after_ctf)
|
||||||
verify_emails = set_config('verify_emails', verify_emails)
|
verify_emails = utils.set_config('verify_emails', verify_emails)
|
||||||
mail_tls = set_config('mail_tls', mail_tls)
|
mail_tls = utils.set_config('mail_tls', mail_tls)
|
||||||
mail_ssl = set_config('mail_ssl', mail_ssl)
|
mail_ssl = utils.set_config('mail_ssl', mail_ssl)
|
||||||
|
|
||||||
mail_server = set_config("mail_server", request.form.get('mail_server', None))
|
mail_server = utils.set_config("mail_server", request.form.get('mail_server', None))
|
||||||
mail_port = set_config("mail_port", request.form.get('mail_port', None))
|
mail_port = utils.set_config("mail_port", request.form.get('mail_port', None))
|
||||||
|
|
||||||
mail_username = set_config("mail_username", request.form.get('mail_username', None))
|
mail_username = utils.set_config("mail_username", request.form.get('mail_username', None))
|
||||||
mail_password = set_config("mail_password", request.form.get('mail_password', None))
|
mail_password = utils.set_config("mail_password", request.form.get('mail_password', None))
|
||||||
|
|
||||||
ctf_name = set_config("ctf_name", request.form.get('ctf_name', None))
|
ctf_name = utils.set_config("ctf_name", request.form.get('ctf_name', None))
|
||||||
ctf_theme = set_config("ctf_theme", request.form.get('ctf_theme', None))
|
ctf_theme = utils.set_config("ctf_theme", request.form.get('ctf_theme', None))
|
||||||
|
|
||||||
mailfrom_addr = set_config("mailfrom_addr", request.form.get('mailfrom_addr', None))
|
mailfrom_addr = utils.set_config("mailfrom_addr", request.form.get('mailfrom_addr', None))
|
||||||
mg_base_url = set_config("mg_base_url", request.form.get('mg_base_url', None))
|
mg_base_url = utils.set_config("mg_base_url", request.form.get('mg_base_url', None))
|
||||||
mg_api_key = set_config("mg_api_key", request.form.get('mg_api_key', None))
|
mg_api_key = utils.set_config("mg_api_key", request.form.get('mg_api_key', None))
|
||||||
|
|
||||||
db_start = Config.query.filter_by(key='start').first()
|
db_start = Config.query.filter_by(key='start').first()
|
||||||
db_start.value = start
|
db_start.value = start
|
||||||
@@ -120,36 +120,36 @@ def admin_config():
|
|||||||
|
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
cache.clear()
|
cache.clear()
|
||||||
ctf_name = get_config('ctf_name')
|
ctf_name = utils.get_config('ctf_name')
|
||||||
ctf_theme = get_config('ctf_theme')
|
ctf_theme = utils.get_config('ctf_theme')
|
||||||
hide_scores = get_config('hide_scores')
|
hide_scores = utils.get_config('hide_scores')
|
||||||
|
|
||||||
mail_server = get_config('mail_server')
|
mail_server = utils.get_config('mail_server')
|
||||||
mail_port = get_config('mail_port')
|
mail_port = utils.get_config('mail_port')
|
||||||
mail_username = get_config('mail_username')
|
mail_username = utils.get_config('mail_username')
|
||||||
mail_password = get_config('mail_password')
|
mail_password = utils.get_config('mail_password')
|
||||||
|
|
||||||
mailfrom_addr = get_config('mailfrom_addr')
|
mailfrom_addr = utils.get_config('mailfrom_addr')
|
||||||
mg_api_key = get_config('mg_api_key')
|
mg_api_key = utils.get_config('mg_api_key')
|
||||||
mg_base_url = get_config('mg_base_url')
|
mg_base_url = utils.get_config('mg_base_url')
|
||||||
|
|
||||||
view_after_ctf = get_config('view_after_ctf')
|
view_after_ctf = utils.get_config('view_after_ctf')
|
||||||
start = get_config('start')
|
start = utils.get_config('start')
|
||||||
end = get_config('end')
|
end = utils.get_config('end')
|
||||||
|
|
||||||
mail_tls = get_config('mail_tls')
|
mail_tls = utils.get_config('mail_tls')
|
||||||
mail_ssl = get_config('mail_ssl')
|
mail_ssl = utils.get_config('mail_ssl')
|
||||||
|
|
||||||
view_challenges_unregistered = get_config('view_challenges_unregistered')
|
view_challenges_unregistered = utils.get_config('view_challenges_unregistered')
|
||||||
view_scoreboard_if_authed = get_config('view_scoreboard_if_authed')
|
view_scoreboard_if_authed = utils.get_config('view_scoreboard_if_authed')
|
||||||
prevent_registration = get_config('prevent_registration')
|
prevent_registration = utils.get_config('prevent_registration')
|
||||||
prevent_name_change = get_config('prevent_name_change')
|
prevent_name_change = utils.get_config('prevent_name_change')
|
||||||
verify_emails = get_config('verify_emails')
|
verify_emails = utils.get_config('verify_emails')
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
db.session.close()
|
db.session.close()
|
||||||
|
|
||||||
themes = get_themes()
|
themes = utils.get_themes()
|
||||||
themes.remove(ctf_theme)
|
themes.remove(ctf_theme)
|
||||||
|
|
||||||
return render_template('admin/config.html',
|
return render_template('admin/config.html',
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
|
from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
|
||||||
from CTFd.utils import admins_only, is_admin, unix_time, get_config, \
|
from CTFd.utils import admins_only, is_admin, cache
|
||||||
set_config, sendmail, rmdir, create_image, delete_image, run_image, container_status, container_ports, \
|
|
||||||
container_stop, container_start, get_themes, cache, upload_file
|
|
||||||
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
||||||
from CTFd.plugins.keys import get_key_class, KEY_CLASSES
|
from CTFd.plugins.keys import get_key_class, KEY_CLASSES
|
||||||
from CTFd.plugins.challenges import get_chal_class, CHALLENGE_CLASSES
|
from CTFd.plugins.challenges import get_chal_class, CHALLENGE_CLASSES
|
||||||
|
|
||||||
|
from CTFd import utils
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
admin_challenges = Blueprint('admin_challenges', __name__)
|
admin_challenges = Blueprint('admin_challenges', __name__)
|
||||||
@@ -109,7 +110,7 @@ def admin_files(chalid):
|
|||||||
files = request.files.getlist('files[]')
|
files = request.files.getlist('files[]')
|
||||||
|
|
||||||
for f in files:
|
for f in files:
|
||||||
upload_file(file=f, chalid=chalid)
|
utils.upload_file(file=f, chalid=chalid)
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
db.session.close()
|
db.session.close()
|
||||||
@@ -162,7 +163,7 @@ def admin_create_chal():
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
for f in files:
|
for f in files:
|
||||||
upload_file(file=f, chalid=chal.id)
|
utils.upload_file(file=f, chalid=chal.id)
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
db.session.close()
|
db.session.close()
|
||||||
@@ -183,7 +184,7 @@ def admin_delete_chal():
|
|||||||
for file in files:
|
for file in files:
|
||||||
upload_folder = app.config['UPLOAD_FOLDER']
|
upload_folder = app.config['UPLOAD_FOLDER']
|
||||||
folder = os.path.dirname(os.path.join(os.path.normpath(app.root_path), upload_folder, file.location))
|
folder = os.path.dirname(os.path.join(os.path.normpath(app.root_path), upload_folder, file.location))
|
||||||
rmdir(folder)
|
utils.rmdir(folder)
|
||||||
Tags.query.filter_by(chal=challenge.id).delete()
|
Tags.query.filter_by(chal=challenge.id).delete()
|
||||||
Challenges.query.filter_by(id=challenge.id).delete()
|
Challenges.query.filter_by(id=challenge.id).delete()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
|
from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
|
||||||
from CTFd.utils import admins_only, is_admin, unix_time, get_config, \
|
from CTFd.utils import admins_only, is_admin, cache
|
||||||
set_config, sendmail, rmdir, create_image, delete_image, run_image, container_status, container_ports, \
|
|
||||||
container_stop, container_start, get_themes, cache, upload_file
|
|
||||||
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
||||||
|
|
||||||
|
from CTFd import utils
|
||||||
|
|
||||||
admin_containers = Blueprint('admin_containers', __name__)
|
admin_containers = Blueprint('admin_containers', __name__)
|
||||||
|
|
||||||
@admin_containers.route('/admin/containers', methods=['GET'])
|
@admin_containers.route('/admin/containers', methods=['GET'])
|
||||||
@@ -11,8 +11,8 @@ admin_containers = Blueprint('admin_containers', __name__)
|
|||||||
def list_container():
|
def list_container():
|
||||||
containers = Containers.query.all()
|
containers = Containers.query.all()
|
||||||
for c in containers:
|
for c in containers:
|
||||||
c.status = container_status(c.name)
|
c.status = utils.container_status(c.name)
|
||||||
c.ports = ', '.join(container_ports(c.name, verbose=True))
|
c.ports = ', '.join(utils.container_ports(c.name, verbose=True))
|
||||||
return render_template('admin/containers.html', containers=containers)
|
return render_template('admin/containers.html', containers=containers)
|
||||||
|
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ def list_container():
|
|||||||
@admins_only
|
@admins_only
|
||||||
def stop_container(container_id):
|
def stop_container(container_id):
|
||||||
container = Containers.query.filter_by(id=container_id).first_or_404()
|
container = Containers.query.filter_by(id=container_id).first_or_404()
|
||||||
if container_stop(container.name):
|
if utils.container_stop(container.name):
|
||||||
return '1'
|
return '1'
|
||||||
else:
|
else:
|
||||||
return '0'
|
return '0'
|
||||||
@@ -30,13 +30,13 @@ def stop_container(container_id):
|
|||||||
@admins_only
|
@admins_only
|
||||||
def run_container(container_id):
|
def run_container(container_id):
|
||||||
container = Containers.query.filter_by(id=container_id).first_or_404()
|
container = Containers.query.filter_by(id=container_id).first_or_404()
|
||||||
if container_status(container.name) == 'missing':
|
if utils.container_status(container.name) == 'missing':
|
||||||
if run_image(container.name):
|
if utils.run_image(container.name):
|
||||||
return '1'
|
return '1'
|
||||||
else:
|
else:
|
||||||
return '0'
|
return '0'
|
||||||
else:
|
else:
|
||||||
if container_start(container.name):
|
if utils.container_start(container.name):
|
||||||
return '1'
|
return '1'
|
||||||
else:
|
else:
|
||||||
return '0'
|
return '0'
|
||||||
@@ -46,7 +46,7 @@ def run_container(container_id):
|
|||||||
@admins_only
|
@admins_only
|
||||||
def delete_container(container_id):
|
def delete_container(container_id):
|
||||||
container = Containers.query.filter_by(id=container_id).first_or_404()
|
container = Containers.query.filter_by(id=container_id).first_or_404()
|
||||||
if delete_image(container.name):
|
if utils.delete_image(container.name):
|
||||||
db.session.delete(container)
|
db.session.delete(container)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
db.session.close()
|
db.session.close()
|
||||||
@@ -61,6 +61,6 @@ def new_container():
|
|||||||
return redirect(url_for('admin_containers.list_container'))
|
return redirect(url_for('admin_containers.list_container'))
|
||||||
buildfile = request.form.get('buildfile')
|
buildfile = request.form.get('buildfile')
|
||||||
files = request.files.getlist('files[]')
|
files = request.files.getlist('files[]')
|
||||||
create_image(name=name, buildfile=buildfile, files=files)
|
utils.create_image(name=name, buildfile=buildfile, files=files)
|
||||||
run_image(name)
|
utils.run_image(name)
|
||||||
return redirect(url_for('admin_containers.list_container'))
|
return redirect(url_for('admin_containers.list_container'))
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
|
from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
|
||||||
from CTFd.utils import admins_only, is_admin, unix_time, get_config, \
|
from CTFd.utils import admins_only, is_admin, cache
|
||||||
set_config, sendmail, rmdir, create_image, delete_image, run_image, container_status, container_ports, \
|
|
||||||
container_stop, container_start, get_themes, cache, upload_file
|
|
||||||
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
||||||
from CTFd.plugins.keys import get_key_class, KEY_CLASSES
|
from CTFd.plugins.keys import get_key_class, KEY_CLASSES
|
||||||
|
|
||||||
|
from CTFd import utils
|
||||||
|
|
||||||
admin_keys = Blueprint('admin_keys', __name__)
|
admin_keys = Blueprint('admin_keys', __name__)
|
||||||
|
|
||||||
@admin_keys.route('/admin/key_types', methods=['GET'])
|
@admin_keys.route('/admin/key_types', methods=['GET'])
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
|
from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
|
||||||
from CTFd.utils import admins_only, is_admin, unix_time, get_config, \
|
from CTFd.utils import admins_only, is_admin, cache
|
||||||
set_config, sendmail, rmdir, create_image, delete_image, run_image, container_status, container_ports, \
|
|
||||||
container_stop, container_start, get_themes, cache, upload_file
|
|
||||||
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
||||||
|
|
||||||
|
from CTFd import utils
|
||||||
|
|
||||||
admin_pages = Blueprint('admin_pages', __name__)
|
admin_pages = Blueprint('admin_pages', __name__)
|
||||||
|
|
||||||
@admin_pages.route('/admin/css', methods=['GET', 'POST'])
|
@admin_pages.route('/admin/css', methods=['GET', 'POST'])
|
||||||
@@ -11,7 +11,7 @@ admin_pages = Blueprint('admin_pages', __name__)
|
|||||||
def admin_css():
|
def admin_css():
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
css = request.form['css']
|
css = request.form['css']
|
||||||
css = set_config('css', css)
|
css = utils.set_config('css', css)
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
cache.clear()
|
cache.clear()
|
||||||
return '1'
|
return '1'
|
||||||
@@ -49,7 +49,7 @@ def admin_pages_view(route):
|
|||||||
db.session.close()
|
db.session.close()
|
||||||
return redirect(url_for('admin_pages.admin_pages_view'))
|
return redirect(url_for('admin_pages.admin_pages_view'))
|
||||||
pages = Pages.query.all()
|
pages = Pages.query.all()
|
||||||
return render_template('admin/pages.html', routes=pages, css=get_config('css'))
|
return render_template('admin/pages.html', routes=pages, css=utils.get_config('css'))
|
||||||
|
|
||||||
|
|
||||||
@admin_pages.route('/admin/page/<pageroute>/delete', methods=['POST'])
|
@admin_pages.route('/admin/page/<pageroute>/delete', methods=['POST'])
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
|
from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
|
||||||
from CTFd.utils import admins_only, is_admin, unix_time, get_config, \
|
from CTFd.utils import admins_only, is_admin, cache
|
||||||
set_config, sendmail, rmdir, create_image, delete_image, run_image, container_status, container_ports, \
|
|
||||||
container_stop, container_start, get_themes, cache, upload_file
|
|
||||||
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
||||||
from CTFd.scoreboard import get_standings
|
from CTFd.scoreboard import get_standings
|
||||||
|
|
||||||
|
from CTFd import utils
|
||||||
|
|
||||||
admin_scoreboard = Blueprint('admin_scoreboard', __name__)
|
admin_scoreboard = Blueprint('admin_scoreboard', __name__)
|
||||||
|
|
||||||
@admin_scoreboard.route('/admin/scoreboard')
|
@admin_scoreboard.route('/admin/scoreboard')
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
|
from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
|
||||||
from CTFd.utils import admins_only, is_admin, unix_time, get_config, \
|
from CTFd.utils import admins_only, is_admin, cache
|
||||||
set_config, sendmail, rmdir, create_image, delete_image, run_image, container_status, container_ports, \
|
|
||||||
container_stop, container_start, get_themes, cache, upload_file
|
|
||||||
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
||||||
|
|
||||||
|
from CTFd import utils
|
||||||
|
|
||||||
admin_statistics = Blueprint('admin_statistics', __name__)
|
admin_statistics = Blueprint('admin_statistics', __name__)
|
||||||
|
|
||||||
@admin_statistics.route('/admin/graphs')
|
@admin_statistics.route('/admin/graphs')
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
|
from flask import current_app as app, render_template, request, redirect, jsonify, url_for, Blueprint
|
||||||
from CTFd.utils import admins_only, is_admin, unix_time, get_config, \
|
from CTFd.utils import admins_only, is_admin, cache
|
||||||
set_config, sendmail, rmdir, create_image, delete_image, run_image, container_status, container_ports, \
|
|
||||||
container_stop, container_start, get_themes, cache, upload_file
|
|
||||||
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
from CTFd.models import db, Teams, Solves, Awards, Containers, Challenges, WrongKeys, Keys, Tags, Files, Tracking, Pages, Config, DatabaseError
|
||||||
from passlib.hash import bcrypt_sha256
|
from passlib.hash import bcrypt_sha256
|
||||||
from sqlalchemy.sql import not_
|
from sqlalchemy.sql import not_
|
||||||
|
|
||||||
|
from CTFd import utils
|
||||||
|
|
||||||
admin_teams = Blueprint('admin_teams', __name__)
|
admin_teams = Blueprint('admin_teams', __name__)
|
||||||
|
|
||||||
@admin_teams.route('/admin/teams', defaults={'page': '1'})
|
@admin_teams.route('/admin/teams', defaults={'page': '1'})
|
||||||
@@ -84,6 +84,7 @@ def admin_team(teamid):
|
|||||||
return jsonify({'data': errors})
|
return jsonify({'data': errors})
|
||||||
else:
|
else:
|
||||||
user.name = name
|
user.name = name
|
||||||
|
if email:
|
||||||
user.email = email
|
user.email = email
|
||||||
if password:
|
if password:
|
||||||
user.password = bcrypt_sha256.encrypt(password)
|
user.password = bcrypt_sha256.encrypt(password)
|
||||||
@@ -101,7 +102,7 @@ def email_user(teamid):
|
|||||||
message = request.form.get('msg', None)
|
message = request.form.get('msg', None)
|
||||||
team = Teams.query.filter(Teams.id == teamid).first()
|
team = Teams.query.filter(Teams.id == teamid).first()
|
||||||
if message and team:
|
if message and team:
|
||||||
if sendmail(team.email, message):
|
if utils.sendmail(team.email, message):
|
||||||
return '1'
|
return '1'
|
||||||
return '0'
|
return '0'
|
||||||
|
|
||||||
@@ -160,7 +161,7 @@ def admin_solves(teamid="all"):
|
|||||||
'team': x.teamid,
|
'team': x.teamid,
|
||||||
'value': x.chal.value,
|
'value': x.chal.value,
|
||||||
'category': x.chal.category,
|
'category': x.chal.category,
|
||||||
'time': unix_time(x.date)
|
'time': utils.unix_time(x.date)
|
||||||
})
|
})
|
||||||
for award in awards:
|
for award in awards:
|
||||||
json_data['solves'].append({
|
json_data['solves'].append({
|
||||||
@@ -169,7 +170,7 @@ def admin_solves(teamid="all"):
|
|||||||
'team': award.teamid,
|
'team': award.teamid,
|
||||||
'value': award.value,
|
'value': award.value,
|
||||||
'category': award.category or "Award",
|
'category': award.category or "Award",
|
||||||
'time': unix_time(award.date)
|
'time': utils.unix_time(award.date)
|
||||||
})
|
})
|
||||||
json_data['solves'].sort(key=lambda k: k['time'])
|
json_data['solves'].sort(key=lambda k: k['time'])
|
||||||
return jsonify(json_data)
|
return jsonify(json_data)
|
||||||
|
|||||||
28
CTFd/auth.py
28
CTFd/auth.py
@@ -8,8 +8,8 @@ from flask import current_app as app, render_template, request, redirect, url_fo
|
|||||||
from itsdangerous import TimedSerializer, BadTimeSignature, Signer, BadSignature
|
from itsdangerous import TimedSerializer, BadTimeSignature, Signer, BadSignature
|
||||||
from passlib.hash import bcrypt_sha256
|
from passlib.hash import bcrypt_sha256
|
||||||
|
|
||||||
from CTFd.utils import sha512, is_safe_url, authed, can_send_mail, sendmail, can_register, get_config, verify_email
|
|
||||||
from CTFd.models import db, Teams
|
from CTFd.models import db, Teams
|
||||||
|
from CTFd import utils
|
||||||
|
|
||||||
auth = Blueprint('auth', __name__)
|
auth = Blueprint('auth', __name__)
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ auth = Blueprint('auth', __name__)
|
|||||||
@auth.route('/confirm', methods=['POST', 'GET'])
|
@auth.route('/confirm', methods=['POST', 'GET'])
|
||||||
@auth.route('/confirm/<data>', methods=['GET'])
|
@auth.route('/confirm/<data>', methods=['GET'])
|
||||||
def confirm_user(data=None):
|
def confirm_user(data=None):
|
||||||
if not get_config('verify_emails'):
|
if not utils.get_config('verify_emails'):
|
||||||
return redirect(url_for('challenges.challenges_view'))
|
return redirect(url_for('challenges.challenges_view'))
|
||||||
if data and request.method == "GET": # User is confirming email account
|
if data and request.method == "GET": # User is confirming email account
|
||||||
try:
|
try:
|
||||||
@@ -33,17 +33,17 @@ def confirm_user(data=None):
|
|||||||
logger = logging.getLogger('regs')
|
logger = logging.getLogger('regs')
|
||||||
logger.warn("[{0}] {1} confirmed {2}".format(time.strftime("%m/%d/%Y %X"), team.name.encode('utf-8'), team.email.encode('utf-8')))
|
logger.warn("[{0}] {1} confirmed {2}".format(time.strftime("%m/%d/%Y %X"), team.name.encode('utf-8'), team.email.encode('utf-8')))
|
||||||
db.session.close()
|
db.session.close()
|
||||||
if authed():
|
if utils.authed():
|
||||||
return redirect(url_for('challenges.challenges_view'))
|
return redirect(url_for('challenges.challenges_view'))
|
||||||
return redirect(url_for('auth.login'))
|
return redirect(url_for('auth.login'))
|
||||||
if not data and request.method == "GET": # User has been directed to the confirm page because his account is not verified
|
if not data and request.method == "GET": # User has been directed to the confirm page because his account is not verified
|
||||||
if not authed():
|
if not utils.authed():
|
||||||
return redirect(url_for('auth.login'))
|
return redirect(url_for('auth.login'))
|
||||||
team = Teams.query.filter_by(id=session['id']).first_or_404()
|
team = Teams.query.filter_by(id=session['id']).first_or_404()
|
||||||
if team.verified:
|
if team.verified:
|
||||||
return redirect(url_for('views.profile'))
|
return redirect(url_for('views.profile'))
|
||||||
else:
|
else:
|
||||||
verify_email(team.email)
|
utils.verify_email(team.email)
|
||||||
return render_template('confirm.html', team=team)
|
return render_template('confirm.html', team=team)
|
||||||
|
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ Did you initiate a password reset?
|
|||||||
|
|
||||||
""".format(url_for('auth.reset_password', _external=True), urllib.quote_plus(token.encode('base64')))
|
""".format(url_for('auth.reset_password', _external=True), urllib.quote_plus(token.encode('base64')))
|
||||||
|
|
||||||
sendmail(email, text)
|
utils.sendmail(email, text)
|
||||||
|
|
||||||
return render_template('reset_password.html', errors=['If that account exists you will receive an email, please check your inbox'])
|
return render_template('reset_password.html', errors=['If that account exists you will receive an email, please check your inbox'])
|
||||||
return render_template('reset_password.html')
|
return render_template('reset_password.html')
|
||||||
@@ -88,7 +88,7 @@ Did you initiate a password reset?
|
|||||||
|
|
||||||
@auth.route('/register', methods=['POST', 'GET'])
|
@auth.route('/register', methods=['POST', 'GET'])
|
||||||
def register():
|
def register():
|
||||||
if not can_register():
|
if not utils.can_register():
|
||||||
return redirect(url_for('auth.login'))
|
return redirect(url_for('auth.login'))
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
errors = []
|
errors = []
|
||||||
@@ -128,9 +128,9 @@ def register():
|
|||||||
session['username'] = team.name
|
session['username'] = team.name
|
||||||
session['id'] = team.id
|
session['id'] = team.id
|
||||||
session['admin'] = team.admin
|
session['admin'] = team.admin
|
||||||
session['nonce'] = sha512(os.urandom(10))
|
session['nonce'] = utils.sha512(os.urandom(10))
|
||||||
|
|
||||||
if can_send_mail() and get_config('verify_emails'): # Confirming users is enabled and we can send email.
|
if utils.can_send_mail() and utils.get_config('verify_emails'): # Confirming users is enabled and we can send email.
|
||||||
db.session.close()
|
db.session.close()
|
||||||
logger = logging.getLogger('regs')
|
logger = logging.getLogger('regs')
|
||||||
logger.warn("[{0}] {1} registered (UNCONFIRMED) with {2}".format(time.strftime("%m/%d/%Y %X"),
|
logger.warn("[{0}] {1} registered (UNCONFIRMED) with {2}".format(time.strftime("%m/%d/%Y %X"),
|
||||||
@@ -138,8 +138,8 @@ def register():
|
|||||||
request.form['email'].encode('utf-8')))
|
request.form['email'].encode('utf-8')))
|
||||||
return redirect(url_for('auth.confirm_user'))
|
return redirect(url_for('auth.confirm_user'))
|
||||||
else: # Don't care about confirming users
|
else: # Don't care about confirming users
|
||||||
if can_send_mail(): # We want to notify the user that they have registered.
|
if utils.can_send_mail(): # We want to notify the user that they have registered.
|
||||||
sendmail(request.form['email'], "You've successfully registered for {}".format(get_config('ctf_name')))
|
utils.sendmail(request.form['email'], "You've successfully registered for {}".format(utils.get_config('ctf_name')))
|
||||||
|
|
||||||
db.session.close()
|
db.session.close()
|
||||||
|
|
||||||
@@ -165,13 +165,13 @@ def login():
|
|||||||
session['username'] = team.name
|
session['username'] = team.name
|
||||||
session['id'] = team.id
|
session['id'] = team.id
|
||||||
session['admin'] = team.admin
|
session['admin'] = team.admin
|
||||||
session['nonce'] = sha512(os.urandom(10))
|
session['nonce'] = utils.sha512(os.urandom(10))
|
||||||
db.session.close()
|
db.session.close()
|
||||||
|
|
||||||
logger = logging.getLogger('logins')
|
logger = logging.getLogger('logins')
|
||||||
logger.warn("[{0}] {1} logged in".format(time.strftime("%m/%d/%Y %X"), session['username'].encode('utf-8')))
|
logger.warn("[{0}] {1} logged in".format(time.strftime("%m/%d/%Y %X"), session['username'].encode('utf-8')))
|
||||||
|
|
||||||
if request.args.get('next') and is_safe_url(request.args.get('next')):
|
if request.args.get('next') and utils.is_safe_url(request.args.get('next')):
|
||||||
return redirect(request.args.get('next'))
|
return redirect(request.args.get('next'))
|
||||||
return redirect(url_for('challenges.challenges_view'))
|
return redirect(url_for('challenges.challenges_view'))
|
||||||
else: # This user exists but the password is wrong
|
else: # This user exists but the password is wrong
|
||||||
@@ -189,6 +189,6 @@ def login():
|
|||||||
|
|
||||||
@auth.route('/logout')
|
@auth.route('/logout')
|
||||||
def logout():
|
def logout():
|
||||||
if authed():
|
if utils.authed():
|
||||||
session.clear()
|
session.clear()
|
||||||
return redirect(url_for('views.static_html'))
|
return redirect(url_for('views.static_html'))
|
||||||
|
|||||||
@@ -6,37 +6,38 @@ import time
|
|||||||
from flask import render_template, request, redirect, jsonify, url_for, session, Blueprint
|
from flask import render_template, request, redirect, jsonify, url_for, session, Blueprint
|
||||||
from sqlalchemy.sql import or_
|
from sqlalchemy.sql import or_
|
||||||
|
|
||||||
from CTFd.utils import ctftime, view_after_ctf, authed, unix_time, get_kpm, user_can_view_challenges, is_admin, get_config, get_ip, is_verified, ctf_started, ctf_ended, ctf_name, hide_scores
|
|
||||||
from CTFd.models import db, Challenges, Files, Solves, WrongKeys, Keys, Tags, Teams, Awards
|
from CTFd.models import db, Challenges, Files, Solves, WrongKeys, Keys, Tags, Teams, Awards
|
||||||
from CTFd.plugins.keys import get_key_class
|
from CTFd.plugins.keys import get_key_class
|
||||||
from CTFd.plugins.challenges import get_chal_class
|
from CTFd.plugins.challenges import get_chal_class
|
||||||
|
|
||||||
|
from CTFd import utils
|
||||||
|
|
||||||
challenges = Blueprint('challenges', __name__)
|
challenges = Blueprint('challenges', __name__)
|
||||||
|
|
||||||
|
|
||||||
@challenges.route('/challenges', methods=['GET'])
|
@challenges.route('/challenges', methods=['GET'])
|
||||||
def challenges_view():
|
def challenges_view():
|
||||||
errors = []
|
errors = []
|
||||||
start = get_config('start') or 0
|
start = utils.get_config('start') or 0
|
||||||
end = get_config('end') or 0
|
end = utils.get_config('end') or 0
|
||||||
if not is_admin(): # User is not an admin
|
if not utils.is_admin(): # User is not an admin
|
||||||
if not ctftime():
|
if not utils.ctftime():
|
||||||
# It is not CTF time
|
# It is not CTF time
|
||||||
if view_after_ctf(): # But we are allowed to view after the CTF ends
|
if utils.view_after_ctf(): # But we are allowed to view after the CTF ends
|
||||||
pass
|
pass
|
||||||
else: # We are NOT allowed to view after the CTF ends
|
else: # We are NOT allowed to view after the CTF ends
|
||||||
if get_config('start') and not ctf_started():
|
if utils.get_config('start') and not utils.ctf_started():
|
||||||
errors.append('{} has not started yet'.format(ctf_name()))
|
errors.append('{} has not started yet'.format(utils.ctf_name()))
|
||||||
if (get_config('end') and ctf_ended()) and not view_after_ctf():
|
if (utils.get_config('end') and utils.ctf_ended()) and not utils.view_after_ctf():
|
||||||
errors.append('{} has ended'.format(ctf_name()))
|
errors.append('{} has ended'.format(utils.ctf_name()))
|
||||||
return render_template('chals.html', errors=errors, start=int(start), end=int(end))
|
return render_template('chals.html', errors=errors, start=int(start), end=int(end))
|
||||||
if get_config('verify_emails') and not is_verified(): # User is not confirmed
|
if utils.get_config('verify_emails') and not utils.is_verified(): # User is not confirmed
|
||||||
return redirect(url_for('auth.confirm_user'))
|
return redirect(url_for('auth.confirm_user'))
|
||||||
if user_can_view_challenges(): # Do we allow unauthenticated users?
|
if utils.user_can_view_challenges(): # Do we allow unauthenticated users?
|
||||||
if get_config('start') and not ctf_started():
|
if utils.get_config('start') and not utils.ctf_started():
|
||||||
errors.append('{} has not started yet'.format(ctf_name()))
|
errors.append('{} has not started yet'.format(utils.ctf_name()))
|
||||||
if (get_config('end') and ctf_ended()) and not view_after_ctf():
|
if (utils.get_config('end') and utils.ctf_ended()) and not utils.view_after_ctf():
|
||||||
errors.append('{} has ended'.format(ctf_name()))
|
errors.append('{} has ended'.format(utils.ctf_name()))
|
||||||
return render_template('chals.html', errors=errors, start=int(start), end=int(end))
|
return render_template('chals.html', errors=errors, start=int(start), end=int(end))
|
||||||
else:
|
else:
|
||||||
return redirect(url_for('auth.login', next='challenges'))
|
return redirect(url_for('auth.login', next='challenges'))
|
||||||
@@ -44,13 +45,13 @@ def challenges_view():
|
|||||||
|
|
||||||
@challenges.route('/chals', methods=['GET'])
|
@challenges.route('/chals', methods=['GET'])
|
||||||
def chals():
|
def chals():
|
||||||
if not is_admin():
|
if not utils.is_admin():
|
||||||
if not ctftime():
|
if not utils.ctftime():
|
||||||
if view_after_ctf():
|
if utils.view_after_ctf():
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
return redirect(url_for('views.static_html'))
|
return redirect(url_for('views.static_html'))
|
||||||
if user_can_view_challenges() and (ctf_started() or is_admin()):
|
if utils.user_can_view_challenges() and (utils.ctf_started() or utils.is_admin()):
|
||||||
chals = Challenges.query.filter(or_(Challenges.hidden != True, Challenges.hidden == None)).order_by(Challenges.value).all()
|
chals = Challenges.query.filter(or_(Challenges.hidden != True, Challenges.hidden == None)).order_by(Challenges.value).all()
|
||||||
json = {'game': []}
|
json = {'game': []}
|
||||||
for x in chals:
|
for x in chals:
|
||||||
@@ -77,14 +78,14 @@ def chals():
|
|||||||
|
|
||||||
@challenges.route('/chals/solves')
|
@challenges.route('/chals/solves')
|
||||||
def solves_per_chal():
|
def solves_per_chal():
|
||||||
if not user_can_view_challenges():
|
if not utils.user_can_view_challenges():
|
||||||
return redirect(url_for('auth.login', next=request.path))
|
return redirect(url_for('auth.login', next=request.path))
|
||||||
|
|
||||||
solves_sub = db.session.query(Solves.chalid, db.func.count(Solves.chalid).label('solves')).join(Teams, Solves.teamid == Teams.id).filter(Teams.banned == False).group_by(Solves.chalid).subquery()
|
solves_sub = db.session.query(Solves.chalid, db.func.count(Solves.chalid).label('solves')).join(Teams, Solves.teamid == Teams.id).filter(Teams.banned == False).group_by(Solves.chalid).subquery()
|
||||||
solves = db.session.query(solves_sub.columns.chalid, solves_sub.columns.solves, Challenges.name) \
|
solves = db.session.query(solves_sub.columns.chalid, solves_sub.columns.solves, Challenges.name) \
|
||||||
.join(Challenges, solves_sub.columns.chalid == Challenges.id).all()
|
.join(Challenges, solves_sub.columns.chalid == Challenges.id).all()
|
||||||
json = {}
|
json = {}
|
||||||
if hide_scores():
|
if utils.hide_scores():
|
||||||
for chal, count, name in solves:
|
for chal, count, name in solves:
|
||||||
json[chal] = -1
|
json[chal] = -1
|
||||||
else:
|
else:
|
||||||
@@ -100,10 +101,10 @@ def solves(teamid=None):
|
|||||||
solves = None
|
solves = None
|
||||||
awards = None
|
awards = None
|
||||||
if teamid is None:
|
if teamid is None:
|
||||||
if is_admin():
|
if utils.is_admin():
|
||||||
solves = Solves.query.filter_by(teamid=session['id']).all()
|
solves = Solves.query.filter_by(teamid=session['id']).all()
|
||||||
elif user_can_view_challenges():
|
elif utils.user_can_view_challenges():
|
||||||
if authed():
|
if utils.authed():
|
||||||
solves = Solves.query.join(Teams, Solves.teamid == Teams.id).filter(Solves.teamid == session['id'], Teams.banned == False).all()
|
solves = Solves.query.join(Teams, Solves.teamid == Teams.id).filter(Solves.teamid == session['id'], Teams.banned == False).all()
|
||||||
else:
|
else:
|
||||||
return jsonify({'solves': []})
|
return jsonify({'solves': []})
|
||||||
@@ -121,7 +122,7 @@ def solves(teamid=None):
|
|||||||
'team': solve.teamid,
|
'team': solve.teamid,
|
||||||
'value': solve.chal.value,
|
'value': solve.chal.value,
|
||||||
'category': solve.chal.category,
|
'category': solve.chal.category,
|
||||||
'time': unix_time(solve.date)
|
'time': utils.unix_time(solve.date)
|
||||||
})
|
})
|
||||||
if awards:
|
if awards:
|
||||||
for award in awards:
|
for award in awards:
|
||||||
@@ -131,7 +132,7 @@ def solves(teamid=None):
|
|||||||
'team': award.teamid,
|
'team': award.teamid,
|
||||||
'value': award.value,
|
'value': award.value,
|
||||||
'category': award.category or "Award",
|
'category': award.category or "Award",
|
||||||
'time': unix_time(award.date)
|
'time': utils.unix_time(award.date)
|
||||||
})
|
})
|
||||||
json['solves'].sort(key=lambda k: k['time'])
|
json['solves'].sort(key=lambda k: k['time'])
|
||||||
return jsonify(json)
|
return jsonify(json)
|
||||||
@@ -139,13 +140,13 @@ def solves(teamid=None):
|
|||||||
|
|
||||||
@challenges.route('/maxattempts')
|
@challenges.route('/maxattempts')
|
||||||
def attempts():
|
def attempts():
|
||||||
if not user_can_view_challenges():
|
if not utils.user_can_view_challenges():
|
||||||
return redirect(url_for('auth.login', next=request.path))
|
return redirect(url_for('auth.login', next=request.path))
|
||||||
chals = Challenges.query.add_columns('id').all()
|
chals = Challenges.query.add_columns('id').all()
|
||||||
json = {'maxattempts': []}
|
json = {'maxattempts': []}
|
||||||
for chal, chalid in chals:
|
for chal, chalid in chals:
|
||||||
fails = WrongKeys.query.filter_by(teamid=session['id'], chalid=chalid).count()
|
fails = WrongKeys.query.filter_by(teamid=session['id'], chalid=chalid).count()
|
||||||
if fails >= int(get_config("max_tries")) and int(get_config("max_tries")) > 0:
|
if fails >= int(utils.get_config("max_tries")) and int(utils.get_config("max_tries")) > 0:
|
||||||
json['maxattempts'].append({'chalid': chalid})
|
json['maxattempts'].append({'chalid': chalid})
|
||||||
return jsonify(json)
|
return jsonify(json)
|
||||||
|
|
||||||
@@ -161,11 +162,11 @@ def fails(teamid):
|
|||||||
|
|
||||||
@challenges.route('/chal/<int:chalid>/solves', methods=['GET'])
|
@challenges.route('/chal/<int:chalid>/solves', methods=['GET'])
|
||||||
def who_solved(chalid):
|
def who_solved(chalid):
|
||||||
if not user_can_view_challenges():
|
if not utils.user_can_view_challenges():
|
||||||
return redirect(url_for('auth.login', next=request.path))
|
return redirect(url_for('auth.login', next=request.path))
|
||||||
|
|
||||||
json = {'teams': []}
|
json = {'teams': []}
|
||||||
if hide_scores():
|
if utils.hide_scores():
|
||||||
return jsonify(json)
|
return jsonify(json)
|
||||||
solves = Solves.query.join(Teams, Solves.teamid == Teams.id).filter(Solves.chalid == chalid, Teams.banned == False).order_by(Solves.date.asc())
|
solves = Solves.query.join(Teams, Solves.teamid == Teams.id).filter(Solves.chalid == chalid, Teams.banned == False).order_by(Solves.date.asc())
|
||||||
for solve in solves:
|
for solve in solves:
|
||||||
@@ -175,19 +176,19 @@ def who_solved(chalid):
|
|||||||
|
|
||||||
@challenges.route('/chal/<int:chalid>', methods=['POST'])
|
@challenges.route('/chal/<int:chalid>', methods=['POST'])
|
||||||
def chal(chalid):
|
def chal(chalid):
|
||||||
if ctf_ended() and not view_after_ctf():
|
if utils.ctf_ended() and not utils.view_after_ctf():
|
||||||
return redirect(url_for('challenges.challenges_view'))
|
return redirect(url_for('challenges.challenges_view'))
|
||||||
if not user_can_view_challenges():
|
if not utils.user_can_view_challenges():
|
||||||
return redirect(url_for('auth.login', next=request.path))
|
return redirect(url_for('auth.login', next=request.path))
|
||||||
if authed() and is_verified() and (ctf_started() or view_after_ctf()):
|
if utils.authed() and utils.is_verified() and (utils.ctf_started() or utils.view_after_ctf()):
|
||||||
fails = WrongKeys.query.filter_by(teamid=session['id'], chalid=chalid).count()
|
fails = WrongKeys.query.filter_by(teamid=session['id'], chalid=chalid).count()
|
||||||
logger = logging.getLogger('keys')
|
logger = logging.getLogger('keys')
|
||||||
data = (time.strftime("%m/%d/%Y %X"), session['username'].encode('utf-8'), request.form['key'].encode('utf-8'), get_kpm(session['id']))
|
data = (time.strftime("%m/%d/%Y %X"), session['username'].encode('utf-8'), request.form['key'].encode('utf-8'), utils.get_kpm(session['id']))
|
||||||
print("[{0}] {1} submitted {2} with kpm {3}".format(*data))
|
print("[{0}] {1} submitted {2} with kpm {3}".format(*data))
|
||||||
|
|
||||||
# Anti-bruteforce / submitting keys too quickly
|
# Anti-bruteforce / submitting keys too quickly
|
||||||
if get_kpm(session['id']) > 10:
|
if utils.get_kpm(session['id']) > 10:
|
||||||
if ctftime():
|
if utils.ctftime():
|
||||||
wrong = WrongKeys(session['id'], chalid, request.form['key'])
|
wrong = WrongKeys(session['id'], chalid, request.form['key'])
|
||||||
db.session.add(wrong)
|
db.session.add(wrong)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@@ -214,15 +215,15 @@ def chal(chalid):
|
|||||||
|
|
||||||
chal_class = get_chal_class(chal.type)
|
chal_class = get_chal_class(chal.type)
|
||||||
if chal_class.solve(chal, provided_key):
|
if chal_class.solve(chal, provided_key):
|
||||||
if ctftime():
|
if utils.ctftime():
|
||||||
solve = Solves(chalid=chalid, teamid=session['id'], ip=get_ip(), flag=provided_key)
|
solve = Solves(chalid=chalid, teamid=session['id'], ip=utils.get_ip(), flag=provided_key)
|
||||||
db.session.add(solve)
|
db.session.add(solve)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
db.session.close()
|
db.session.close()
|
||||||
logger.info("[{0}] {1} submitted {2} with kpm {3} [CORRECT]".format(*data))
|
logger.info("[{0}] {1} submitted {2} with kpm {3} [CORRECT]".format(*data))
|
||||||
return jsonify({'status': '1', 'message': 'Correct'})
|
return jsonify({'status': '1', 'message': 'Correct'})
|
||||||
|
|
||||||
if ctftime():
|
if utils.ctftime():
|
||||||
wrong = WrongKeys(teamid=session['id'], chalid=chalid, flag=provided_key)
|
wrong = WrongKeys(teamid=session['id'], chalid=chalid, flag=provided_key)
|
||||||
db.session.add(wrong)
|
db.session.add(wrong)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
from flask import render_template, jsonify, Blueprint, redirect, url_for, request
|
from flask import render_template, jsonify, Blueprint, redirect, url_for, request
|
||||||
from sqlalchemy.sql.expression import union_all
|
from sqlalchemy.sql.expression import union_all
|
||||||
|
|
||||||
from CTFd.utils import unix_time, authed, get_config, hide_scores
|
|
||||||
from CTFd.models import db, Teams, Solves, Awards, Challenges
|
from CTFd.models import db, Teams, Solves, Awards, Challenges
|
||||||
|
|
||||||
|
from CTFd import utils
|
||||||
|
|
||||||
scoreboard = Blueprint('scoreboard', __name__)
|
scoreboard = Blueprint('scoreboard', __name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -35,9 +36,9 @@ def get_standings(admin=False, count=None):
|
|||||||
|
|
||||||
@scoreboard.route('/scoreboard')
|
@scoreboard.route('/scoreboard')
|
||||||
def scoreboard_view():
|
def scoreboard_view():
|
||||||
if get_config('view_scoreboard_if_authed') and not authed():
|
if utils.get_config('view_scoreboard_if_authed') and not utils.authed():
|
||||||
return redirect(url_for('auth.login', next=request.path))
|
return redirect(url_for('auth.login', next=request.path))
|
||||||
if hide_scores():
|
if utils.hide_scores():
|
||||||
return render_template('scoreboard.html', errors=['Scores are currently hidden'])
|
return render_template('scoreboard.html', errors=['Scores are currently hidden'])
|
||||||
standings = get_standings()
|
standings = get_standings()
|
||||||
return render_template('scoreboard.html', teams=standings)
|
return render_template('scoreboard.html', teams=standings)
|
||||||
@@ -46,9 +47,9 @@ def scoreboard_view():
|
|||||||
@scoreboard.route('/scores')
|
@scoreboard.route('/scores')
|
||||||
def scores():
|
def scores():
|
||||||
json = {'standings': []}
|
json = {'standings': []}
|
||||||
if get_config('view_scoreboard_if_authed') and not authed():
|
if utils.get_config('view_scoreboard_if_authed') and not utils.authed():
|
||||||
return redirect(url_for('auth.login', next=request.path))
|
return redirect(url_for('auth.login', next=request.path))
|
||||||
if hide_scores():
|
if utils.hide_scores():
|
||||||
return jsonify(json)
|
return jsonify(json)
|
||||||
|
|
||||||
standings = get_standings()
|
standings = get_standings()
|
||||||
@@ -61,9 +62,9 @@ def scores():
|
|||||||
@scoreboard.route('/top/<int:count>')
|
@scoreboard.route('/top/<int:count>')
|
||||||
def topteams(count):
|
def topteams(count):
|
||||||
json = {'scores': {}}
|
json = {'scores': {}}
|
||||||
if get_config('view_scoreboard_if_authed') and not authed():
|
if utils.get_config('view_scoreboard_if_authed') and not utils.authed():
|
||||||
return redirect(url_for('auth.login', next=request.path))
|
return redirect(url_for('auth.login', next=request.path))
|
||||||
if hide_scores():
|
if utils.hide_scores():
|
||||||
return jsonify(json)
|
return jsonify(json)
|
||||||
|
|
||||||
if count > 20 or count < 0:
|
if count > 20 or count < 0:
|
||||||
@@ -80,14 +81,14 @@ def topteams(count):
|
|||||||
'chal': x.chalid,
|
'chal': x.chalid,
|
||||||
'team': x.teamid,
|
'team': x.teamid,
|
||||||
'value': x.chal.value,
|
'value': x.chal.value,
|
||||||
'time': unix_time(x.date)
|
'time': utils.unix_time(x.date)
|
||||||
})
|
})
|
||||||
for award in awards:
|
for award in awards:
|
||||||
json['scores'][team.name].append({
|
json['scores'][team.name].append({
|
||||||
'chal': None,
|
'chal': None,
|
||||||
'team': award.teamid,
|
'team': award.teamid,
|
||||||
'value': award.value,
|
'value': award.value,
|
||||||
'time': unix_time(award.date)
|
'time': utils.unix_time(award.date)
|
||||||
})
|
})
|
||||||
json['scores'][team.name] = sorted(json['scores'][team.name], key=lambda k: k['time'])
|
json['scores'][team.name] = sorted(json['scores'][team.name], key=lambda k: k['time'])
|
||||||
return jsonify(json)
|
return jsonify(json)
|
||||||
|
|||||||
@@ -198,8 +198,10 @@ $('#update-user').click(function(e){
|
|||||||
console.log($.grep(user_data, function(e){ return e.name == 'name'; })[0]['value'])
|
console.log($.grep(user_data, function(e){ return e.name == 'name'; })[0]['value'])
|
||||||
console.log(row.find('.team-name > a'))
|
console.log(row.find('.team-name > a'))
|
||||||
row.find('.team-name > a').text( $.grep(user_data, function(e){ return e.name == 'name'; })[0]['value'] );
|
row.find('.team-name > a').text( $.grep(user_data, function(e){ return e.name == 'name'; })[0]['value'] );
|
||||||
row.find('.team-email').text( $.grep(user_data, function(e){ return e.name == 'email'; })[0]['value'] );
|
var new_email = $.grep(user_data, function(e){ return e.name == 'email'; })[0]['value'];
|
||||||
|
if (new_email){
|
||||||
|
row.find('.team-email').text( new_email );
|
||||||
|
}
|
||||||
row.find('.team-website > a').empty()
|
row.find('.team-website > a').empty()
|
||||||
var website = $.grep(user_data, function(e){ return e.name == 'website'; })[0]['value']
|
var website = $.grep(user_data, function(e){ return e.name == 'website'; })[0]['value']
|
||||||
row.find('.team-website').append($('<a>').attr('href', website).text(website));
|
row.find('.team-website').append($('<a>').attr('href', website).text(website));
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ from flask import current_app as app, render_template, request, redirect, abort,
|
|||||||
from jinja2.exceptions import TemplateNotFound
|
from jinja2.exceptions import TemplateNotFound
|
||||||
from passlib.hash import bcrypt_sha256
|
from passlib.hash import bcrypt_sha256
|
||||||
|
|
||||||
from CTFd.utils import authed, is_setup, validate_url, get_config, set_config, sha512, cache, ctftime, view_after_ctf, ctf_started, \
|
|
||||||
is_admin, hide_scores
|
|
||||||
from CTFd.models import db, Teams, Solves, Awards, Files, Pages
|
from CTFd.models import db, Teams, Solves, Awards, Files, Pages
|
||||||
|
from CTFd.utils import cache
|
||||||
|
from CTFd import utils
|
||||||
|
|
||||||
views = Blueprint('views', __name__)
|
views = Blueprint('views', __name__)
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ views = Blueprint('views', __name__)
|
|||||||
def redirect_setup():
|
def redirect_setup():
|
||||||
if request.path.startswith("/static"):
|
if request.path.startswith("/static"):
|
||||||
return
|
return
|
||||||
if not is_setup() and request.path != "/setup":
|
if not utils.is_setup() and request.path != "/setup":
|
||||||
return redirect(url_for('views.setup'))
|
return redirect(url_for('views.setup'))
|
||||||
|
|
||||||
|
|
||||||
@@ -25,15 +25,15 @@ def setup():
|
|||||||
# with app.app_context():
|
# with app.app_context():
|
||||||
# admin = Teams.query.filter_by(admin=True).first()
|
# admin = Teams.query.filter_by(admin=True).first()
|
||||||
|
|
||||||
if not is_setup():
|
if not utils.is_setup():
|
||||||
if not session.get('nonce'):
|
if not session.get('nonce'):
|
||||||
session['nonce'] = sha512(os.urandom(10))
|
session['nonce'] = utils.sha512(os.urandom(10))
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
ctf_name = request.form['ctf_name']
|
ctf_name = request.form['ctf_name']
|
||||||
ctf_name = set_config('ctf_name', ctf_name)
|
ctf_name = utils.set_config('ctf_name', ctf_name)
|
||||||
|
|
||||||
# CSS
|
# CSS
|
||||||
css = set_config('start', '')
|
css = utils.set_config('start', '')
|
||||||
|
|
||||||
# Admin user
|
# Admin user
|
||||||
name = request.form['name']
|
name = request.form['name']
|
||||||
@@ -56,29 +56,29 @@ def setup():
|
|||||||
</div>""".format(request.script_root))
|
</div>""".format(request.script_root))
|
||||||
|
|
||||||
# max attempts per challenge
|
# max attempts per challenge
|
||||||
max_tries = set_config("max_tries", 0)
|
max_tries = utils.set_config("max_tries", 0)
|
||||||
|
|
||||||
# Start time
|
# Start time
|
||||||
start = set_config('start', None)
|
start = utils.set_config('start', None)
|
||||||
end = set_config('end', None)
|
end = utils.set_config('end', None)
|
||||||
|
|
||||||
# Challenges cannot be viewed by unregistered users
|
# Challenges cannot be viewed by unregistered users
|
||||||
view_challenges_unregistered = set_config('view_challenges_unregistered', None)
|
view_challenges_unregistered = utils.set_config('view_challenges_unregistered', None)
|
||||||
|
|
||||||
# Allow/Disallow registration
|
# Allow/Disallow registration
|
||||||
prevent_registration = set_config('prevent_registration', None)
|
prevent_registration = utils.set_config('prevent_registration', None)
|
||||||
|
|
||||||
# Verify emails
|
# Verify emails
|
||||||
verify_emails = set_config('verify_emails', None)
|
verify_emails = utils.set_config('verify_emails', None)
|
||||||
|
|
||||||
mail_server = set_config('mail_server', None)
|
mail_server = utils.set_config('mail_server', None)
|
||||||
mail_port = set_config('mail_port', None)
|
mail_port = utils.set_config('mail_port', None)
|
||||||
mail_tls = set_config('mail_tls', None)
|
mail_tls = utils.set_config('mail_tls', None)
|
||||||
mail_ssl = set_config('mail_ssl', None)
|
mail_ssl = utils.set_config('mail_ssl', None)
|
||||||
mail_username = set_config('mail_username', None)
|
mail_username = utils.set_config('mail_username', None)
|
||||||
mail_password = set_config('mail_password', None)
|
mail_password = utils.set_config('mail_password', None)
|
||||||
|
|
||||||
setup = set_config('setup', True)
|
setup = utils.set_config('setup', True)
|
||||||
|
|
||||||
db.session.add(page)
|
db.session.add(page)
|
||||||
db.session.add(admin)
|
db.session.add(admin)
|
||||||
@@ -87,7 +87,7 @@ def setup():
|
|||||||
session['username'] = admin.name
|
session['username'] = admin.name
|
||||||
session['id'] = admin.id
|
session['id'] = admin.id
|
||||||
session['admin'] = admin.admin
|
session['admin'] = admin.admin
|
||||||
session['nonce'] = sha512(os.urandom(10))
|
session['nonce'] = utils.sha512(os.urandom(10))
|
||||||
|
|
||||||
db.session.close()
|
db.session.close()
|
||||||
app.setup = False
|
app.setup = False
|
||||||
@@ -102,7 +102,7 @@ def setup():
|
|||||||
# Custom CSS handler
|
# Custom CSS handler
|
||||||
@views.route('/static/user.css')
|
@views.route('/static/user.css')
|
||||||
def custom_css():
|
def custom_css():
|
||||||
return Response(get_config("css"), mimetype='text/css')
|
return Response(utils.get_config("css"), mimetype='text/css')
|
||||||
|
|
||||||
|
|
||||||
# Static HTML files
|
# Static HTML files
|
||||||
@@ -124,7 +124,7 @@ def teams(page):
|
|||||||
page_start = results_per_page * (page - 1)
|
page_start = results_per_page * (page - 1)
|
||||||
page_end = results_per_page * (page - 1) + results_per_page
|
page_end = results_per_page * (page - 1) + results_per_page
|
||||||
|
|
||||||
if get_config('verify_emails'):
|
if utils.get_config('verify_emails'):
|
||||||
count = Teams.query.filter_by(verified=True, banned=False).count()
|
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()
|
teams = Teams.query.filter_by(verified=True, banned=False).slice(page_start, page_end).all()
|
||||||
else:
|
else:
|
||||||
@@ -136,7 +136,7 @@ def teams(page):
|
|||||||
|
|
||||||
@views.route('/team/<int:teamid>', methods=['GET', 'POST'])
|
@views.route('/team/<int:teamid>', methods=['GET', 'POST'])
|
||||||
def team(teamid):
|
def team(teamid):
|
||||||
if get_config('view_scoreboard_if_authed') and not authed():
|
if utils.get_config('view_scoreboard_if_utils.authed') and not utils.authed():
|
||||||
return redirect(url_for('auth.login', next=request.path))
|
return redirect(url_for('auth.login', next=request.path))
|
||||||
errors = []
|
errors = []
|
||||||
user = Teams.query.filter_by(id=teamid).first_or_404()
|
user = Teams.query.filter_by(id=teamid).first_or_404()
|
||||||
@@ -146,7 +146,7 @@ def team(teamid):
|
|||||||
place = user.place()
|
place = user.place()
|
||||||
db.session.close()
|
db.session.close()
|
||||||
|
|
||||||
if hide_scores() and teamid != session.get('id'):
|
if utils.hide_scores() and teamid != session.get('id'):
|
||||||
errors.append('Scores are currently hidden')
|
errors.append('Scores are currently hidden')
|
||||||
|
|
||||||
if errors:
|
if errors:
|
||||||
@@ -163,7 +163,7 @@ def team(teamid):
|
|||||||
|
|
||||||
@views.route('/profile', methods=['POST', 'GET'])
|
@views.route('/profile', methods=['POST', 'GET'])
|
||||||
def profile():
|
def profile():
|
||||||
if authed():
|
if utils.authed():
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
errors = []
|
errors = []
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ def profile():
|
|||||||
|
|
||||||
user = Teams.query.filter_by(id=session['id']).first()
|
user = Teams.query.filter_by(id=session['id']).first()
|
||||||
|
|
||||||
if not get_config('prevent_name_change'):
|
if not utils.get_config('prevent_name_change'):
|
||||||
names = Teams.query.filter_by(name=name).first()
|
names = Teams.query.filter_by(name=name).first()
|
||||||
name_len = len(request.form['name']) == 0
|
name_len = len(request.form['name']) == 0
|
||||||
|
|
||||||
@@ -187,13 +187,13 @@ def profile():
|
|||||||
errors.append("Your old password doesn't match what we have.")
|
errors.append("Your old password doesn't match what we have.")
|
||||||
if not valid_email:
|
if not valid_email:
|
||||||
errors.append("That email doesn't look right")
|
errors.append("That email doesn't look right")
|
||||||
if not get_config('prevent_name_change') and names and name != session['username']:
|
if not utils.get_config('prevent_name_change') and names and name != session['username']:
|
||||||
errors.append('That team name is already taken')
|
errors.append('That team name is already taken')
|
||||||
if emails and emails.id != session['id']:
|
if emails and emails.id != session['id']:
|
||||||
errors.append('That email has already been used')
|
errors.append('That email has already been used')
|
||||||
if not get_config('prevent_name_change') and name_len:
|
if not utils.get_config('prevent_name_change') and name_len:
|
||||||
errors.append('Pick a longer team name')
|
errors.append('Pick a longer team name')
|
||||||
if website.strip() and not validate_url(website):
|
if website.strip() and not utils.validate_url(website):
|
||||||
errors.append("That doesn't look like a valid URL")
|
errors.append("That doesn't look like a valid URL")
|
||||||
|
|
||||||
if len(errors) > 0:
|
if len(errors) > 0:
|
||||||
@@ -201,11 +201,11 @@ def profile():
|
|||||||
affiliation=affiliation, country=country, errors=errors)
|
affiliation=affiliation, country=country, errors=errors)
|
||||||
else:
|
else:
|
||||||
team = Teams.query.filter_by(id=session['id']).first()
|
team = Teams.query.filter_by(id=session['id']).first()
|
||||||
if not get_config('prevent_name_change'):
|
if not utils.get_config('prevent_name_change'):
|
||||||
team.name = name
|
team.name = name
|
||||||
if team.email != email.lower():
|
if team.email != email.lower():
|
||||||
team.email = email.lower()
|
team.email = email.lower()
|
||||||
if get_config('verify_emails'):
|
if utils.get_config('verify_emails'):
|
||||||
team.verified = False
|
team.verified = False
|
||||||
session['username'] = team.name
|
session['username'] = team.name
|
||||||
|
|
||||||
@@ -224,8 +224,8 @@ def profile():
|
|||||||
website = user.website
|
website = user.website
|
||||||
affiliation = user.affiliation
|
affiliation = user.affiliation
|
||||||
country = user.country
|
country = user.country
|
||||||
prevent_name_change = get_config('prevent_name_change')
|
prevent_name_change = utils.get_config('prevent_name_change')
|
||||||
confirm_email = get_config('verify_emails') and not user.verified
|
confirm_email = utils.get_config('verify_emails') and not user.verified
|
||||||
return render_template('profile.html', name=name, email=email, website=website, affiliation=affiliation,
|
return render_template('profile.html', name=name, email=email, website=website, affiliation=affiliation,
|
||||||
country=country, prevent_name_change=prevent_name_change, confirm_email=confirm_email)
|
country=country, prevent_name_change=prevent_name_change, confirm_email=confirm_email)
|
||||||
else:
|
else:
|
||||||
@@ -237,9 +237,9 @@ def profile():
|
|||||||
def file_handler(path):
|
def file_handler(path):
|
||||||
f = Files.query.filter_by(location=path).first_or_404()
|
f = Files.query.filter_by(location=path).first_or_404()
|
||||||
if f.chal:
|
if f.chal:
|
||||||
if not is_admin():
|
if not utils.is_admin():
|
||||||
if not ctftime():
|
if not utils.ctftime():
|
||||||
if view_after_ctf() and ctf_started():
|
if utils.view_after_ctf() and utils.ctf_started():
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from CTFd import create_app
|
from CTFd import create_app
|
||||||
|
from CTFd.models import *
|
||||||
from sqlalchemy_utils import database_exists, create_database, drop_database
|
from sqlalchemy_utils import database_exists, create_database, drop_database
|
||||||
from sqlalchemy.engine.url import make_url
|
from sqlalchemy.engine.url import make_url
|
||||||
|
|
||||||
@@ -58,3 +59,62 @@ def login_as_user(app, name="user", password="password"):
|
|||||||
}
|
}
|
||||||
client.post('/login', data=data)
|
client.post('/login', data=data)
|
||||||
return client
|
return client
|
||||||
|
|
||||||
|
|
||||||
|
def gen_challenge(db, name='chal_name', description='chal_description', value=100, category='chal_category', type=0):
|
||||||
|
chal = Challenges(name, description, value, category)
|
||||||
|
db.session.add(chal)
|
||||||
|
db.session.commit()
|
||||||
|
return chal
|
||||||
|
|
||||||
|
|
||||||
|
def gen_award(db, teamid, name="award_name", value=100):
|
||||||
|
award = Awards(teamid, name, value)
|
||||||
|
db.session.add(award)
|
||||||
|
db.session.commit()
|
||||||
|
return award
|
||||||
|
|
||||||
|
|
||||||
|
def gen_tag(db, chal, tag='tag_tag'):
|
||||||
|
tag = Tags(chal, tag)
|
||||||
|
db.session.add(tag)
|
||||||
|
db.session.commit()
|
||||||
|
return tag
|
||||||
|
|
||||||
|
|
||||||
|
def gen_file():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def gen_key(db, chal, flag='flag', key_type=0):
|
||||||
|
key = Keys(chal, flag, key_type)
|
||||||
|
db.session.add(key)
|
||||||
|
db.session.commit()
|
||||||
|
return key
|
||||||
|
|
||||||
|
|
||||||
|
def gen_team(db, name='name', email='user@ctfd.io', password='password'):
|
||||||
|
team = Teams(name, email, password)
|
||||||
|
db.session.add(team)
|
||||||
|
db.session.commit()
|
||||||
|
return team
|
||||||
|
|
||||||
|
|
||||||
|
def gen_solve(db, chalid, teamid, ip='127.0.0.1', flag='rightkey'):
|
||||||
|
solve = Solves(chalid, teamid, ip, flag)
|
||||||
|
db.session.add(solve)
|
||||||
|
db.session.commit()
|
||||||
|
return solve
|
||||||
|
|
||||||
|
def gen_wrongkey(db, teamid, chalid, flag='wrongkey'):
|
||||||
|
wrongkey = WrongKeys(teamid, chalid, flag)
|
||||||
|
db.session.add(wrongkey)
|
||||||
|
db.session.commit()
|
||||||
|
return wrongkey
|
||||||
|
|
||||||
|
|
||||||
|
def gen_tracking(db, ip, team):
|
||||||
|
tracking = Tracking(ip, team)
|
||||||
|
db.session.add(tracking)
|
||||||
|
db.session.commit()
|
||||||
|
return tracking
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
from tests.helpers import create_ctfd, register_user, login_as_user
|
||||||
|
from CTFd.models import Teams
|
||||||
|
|
||||||
|
|
||||||
|
def test_admin_panel():
|
||||||
|
"""Does the admin panel return a 200 by default"""
|
||||||
|
app = create_ctfd()
|
||||||
|
with app.app_context():
|
||||||
|
client = login_as_user(app, name="admin", password="password")
|
||||||
|
r = client.get('/admin')
|
||||||
|
assert r.status_code == 302
|
||||||
|
r = client.get('/admin/graphs')
|
||||||
|
assert r.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_admin_pages():
|
||||||
|
"""Does admin pages return a 200 by default"""
|
||||||
|
app = create_ctfd()
|
||||||
|
with app.app_context():
|
||||||
|
client = login_as_user(app, name="admin", password="password")
|
||||||
|
r = client.get('/admin/pages')
|
||||||
|
assert r.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_admin_teams():
|
||||||
|
"""Does admin teams return a 200 by default"""
|
||||||
|
app = create_ctfd()
|
||||||
|
with app.app_context():
|
||||||
|
client = login_as_user(app, name="admin", password="password")
|
||||||
|
r = client.get('/admin/teams')
|
||||||
|
assert r.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_admin_scoreboard():
|
||||||
|
"""Does admin scoreboard return a 200 by default"""
|
||||||
|
app = create_ctfd()
|
||||||
|
with app.app_context():
|
||||||
|
client = login_as_user(app, name="admin", password="password")
|
||||||
|
r = client.get('/admin/scoreboard')
|
||||||
|
assert r.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_admin_containers():
|
||||||
|
"""Does admin containers return a 200 by default"""
|
||||||
|
app = create_ctfd()
|
||||||
|
with app.app_context():
|
||||||
|
client = login_as_user(app, name="admin", password="password")
|
||||||
|
r = client.get('/admin/containers')
|
||||||
|
assert r.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_admin_chals():
|
||||||
|
"""Does admin chals return a 200 by default"""
|
||||||
|
app = create_ctfd()
|
||||||
|
with app.app_context():
|
||||||
|
client = login_as_user(app, name="admin", password="password")
|
||||||
|
r = client.get('/admin/chals')
|
||||||
|
assert r.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_admin_statistics():
|
||||||
|
"""Does admin statistics return a 200 by default"""
|
||||||
|
app = create_ctfd()
|
||||||
|
with app.app_context():
|
||||||
|
client = login_as_user(app, name="admin", password="password")
|
||||||
|
r = client.get('/admin/statistics')
|
||||||
|
assert r.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_admin_config():
|
||||||
|
"""Does admin config return a 200 by default"""
|
||||||
|
app = create_ctfd()
|
||||||
|
with app.app_context():
|
||||||
|
client = login_as_user(app, name="admin", password="password")
|
||||||
|
r = client.get('/admin/config')
|
||||||
|
assert r.status_code == 200
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
from tests.helpers import create_ctfd, register_user, login_as_user
|
from tests.helpers import create_ctfd, register_user, login_as_user, gen_challenge
|
||||||
from CTFd.models import Teams
|
from CTFd.models import Teams
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
def test_index():
|
def test_index():
|
||||||
@@ -192,3 +193,15 @@ def test_user_get_reset_password():
|
|||||||
client = app.test_client()
|
client = app.test_client()
|
||||||
r = client.get('/reset_password')
|
r = client.get('/reset_password')
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
def test_viewing_challenges():
|
||||||
|
"""Test that users can see added challenges"""
|
||||||
|
app = create_ctfd()
|
||||||
|
with app.app_context():
|
||||||
|
register_user(app)
|
||||||
|
client = login_as_user(app)
|
||||||
|
gen_challenge(app.db)
|
||||||
|
r = client.get('/chals')
|
||||||
|
chals = json.loads(r.data)
|
||||||
|
assert len(chals['game']) == 1
|
||||||
Reference in New Issue
Block a user