mirror of
https://github.com/aljazceru/CTFd.git
synced 2025-12-17 14:04:20 +01:00
General fixes and PEP8 enforcement (#258)
* Fixing index page links when you deploy on a subdirectory * Updating travis for pep8 * autopep8 with just formatting changes
This commit is contained in:
@@ -5,4 +5,5 @@ python:
|
|||||||
install:
|
install:
|
||||||
- pip install -r development.txt
|
- pip install -r development.txt
|
||||||
script:
|
script:
|
||||||
|
- pep8 --ignore E501,E712 CTFd/ tests/
|
||||||
- nosetests
|
- nosetests
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from CTFd import utils
|
|||||||
|
|
||||||
__version__ = '1.0.2'
|
__version__ = '1.0.2'
|
||||||
|
|
||||||
|
|
||||||
class ThemeLoader(FileSystemLoader):
|
class ThemeLoader(FileSystemLoader):
|
||||||
def get_source(self, environment, template):
|
def get_source(self, environment, template):
|
||||||
if template.startswith('admin/'):
|
if template.startswith('admin/'):
|
||||||
@@ -34,21 +35,21 @@ def create_app(config='CTFd.config.Config'):
|
|||||||
if url.drivername == 'postgres':
|
if url.drivername == 'postgres':
|
||||||
url.drivername = 'postgresql'
|
url.drivername = 'postgresql'
|
||||||
|
|
||||||
## Creates database if the database database does not exist
|
# Creates database if the database database does not exist
|
||||||
if not database_exists(url):
|
if not database_exists(url):
|
||||||
create_database(url)
|
create_database(url)
|
||||||
|
|
||||||
## Register database
|
# Register database
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
|
|
||||||
## Register Flask-Migrate
|
# Register Flask-Migrate
|
||||||
migrate.init_app(app, db)
|
migrate.init_app(app, db)
|
||||||
|
|
||||||
## This creates tables instead of db.create_all()
|
# This creates tables instead of db.create_all()
|
||||||
## Allows migrations to happen properly
|
# Allows migrations to happen properly
|
||||||
migrate_upgrade()
|
migrate_upgrade()
|
||||||
|
|
||||||
## Alembic sqlite support is lacking so we should just create_all anyway
|
# Alembic sqlite support is lacking so we should just create_all anyway
|
||||||
if url.drivername.startswith('sqlite'):
|
if url.drivername.startswith('sqlite'):
|
||||||
db.create_all()
|
db.create_all()
|
||||||
|
|
||||||
@@ -59,10 +60,10 @@ def create_app(config='CTFd.config.Config'):
|
|||||||
|
|
||||||
version = utils.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
|
||||||
utils.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! /*\\")
|
||||||
print("/*\\ Please backup your database before proceeding! /*\\")
|
print("/*\\ Please backup your database before proceeding! /*\\")
|
||||||
print("/*\\ CTFd maintainers are not responsible for any data loss! /*\\")
|
print("/*\\ CTFd maintainers are not responsible for any data loss! /*\\")
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ 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'])
|
||||||
@admins_only
|
@admins_only
|
||||||
def list_container():
|
def list_container():
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ 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'])
|
||||||
@admins_only
|
@admins_only
|
||||||
def admin_key_types():
|
def admin_key_types():
|
||||||
@@ -16,6 +17,7 @@ def admin_key_types():
|
|||||||
|
|
||||||
return jsonify(data)
|
return jsonify(data)
|
||||||
|
|
||||||
|
|
||||||
@admin_keys.route('/admin/keys', defaults={'keyid': None}, methods=['POST', 'GET'])
|
@admin_keys.route('/admin/keys', defaults={'keyid': None}, methods=['POST', 'GET'])
|
||||||
@admin_keys.route('/admin/keys/<int:keyid>', methods=['POST', 'GET'])
|
@admin_keys.route('/admin/keys/<int:keyid>', methods=['POST', 'GET'])
|
||||||
@admins_only
|
@admins_only
|
||||||
@@ -53,7 +55,6 @@ def admin_keys_view(keyid):
|
|||||||
return '1'
|
return '1'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@admin_keys.route('/admin/keys/<int:keyid>/delete', methods=['POST'])
|
@admin_keys.route('/admin/keys/<int:keyid>/delete', methods=['POST'])
|
||||||
@admins_only
|
@admins_only
|
||||||
def admin_delete_keys(keyid):
|
def admin_delete_keys(keyid):
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ 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'])
|
||||||
@admins_only
|
@admins_only
|
||||||
def admin_css():
|
def admin_css():
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ 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')
|
||||||
@admins_only
|
@admins_only
|
||||||
def admin_scoreboard_view():
|
def admin_scoreboard_view():
|
||||||
|
|||||||
@@ -6,11 +6,13 @@ 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')
|
||||||
@admins_only
|
@admins_only
|
||||||
def admin_graphs():
|
def admin_graphs():
|
||||||
return render_template('admin/graphs.html')
|
return render_template('admin/graphs.html')
|
||||||
|
|
||||||
|
|
||||||
@admin_statistics.route('/admin/graphs/<graph_type>')
|
@admin_statistics.route('/admin/graphs/<graph_type>')
|
||||||
@admins_only
|
@admins_only
|
||||||
def admin_graph(graph_type):
|
def admin_graph(graph_type):
|
||||||
@@ -31,6 +33,7 @@ def admin_graph(graph_type):
|
|||||||
json_data[name] = count
|
json_data[name] = count
|
||||||
return jsonify(json_data)
|
return jsonify(json_data)
|
||||||
|
|
||||||
|
|
||||||
@admin_statistics.route('/admin/statistics', methods=['GET'])
|
@admin_statistics.route('/admin/statistics', methods=['GET'])
|
||||||
@admins_only
|
@admins_only
|
||||||
def admin_stats():
|
def admin_stats():
|
||||||
@@ -66,6 +69,7 @@ def admin_stats():
|
|||||||
most_solved=most_solved,
|
most_solved=most_solved,
|
||||||
least_solved=least_solved)
|
least_solved=least_solved)
|
||||||
|
|
||||||
|
|
||||||
@admin_statistics.route('/admin/wrong_keys', defaults={'page': '1'}, methods=['GET'])
|
@admin_statistics.route('/admin/wrong_keys', defaults={'page': '1'}, methods=['GET'])
|
||||||
@admin_statistics.route('/admin/wrong_keys/<int:page>', methods=['GET'])
|
@admin_statistics.route('/admin/wrong_keys/<int:page>', methods=['GET'])
|
||||||
@admins_only
|
@admins_only
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ 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'})
|
||||||
@admin_teams.route('/admin/teams/<int:page>')
|
@admin_teams.route('/admin/teams/<int:page>')
|
||||||
@admins_only
|
@admins_only
|
||||||
@@ -225,6 +226,7 @@ def delete_wrong_key(keyid):
|
|||||||
db.session.close()
|
db.session.close()
|
||||||
return '1'
|
return '1'
|
||||||
|
|
||||||
|
|
||||||
@admin_teams.route('/admin/awards/<int:award_id>/delete', methods=['POST'])
|
@admin_teams.route('/admin/awards/<int:award_id>/delete', methods=['POST'])
|
||||||
@admins_only
|
@admins_only
|
||||||
def delete_award(award_id):
|
def delete_award(award_id):
|
||||||
@@ -234,6 +236,7 @@ def delete_award(award_id):
|
|||||||
db.session.close()
|
db.session.close()
|
||||||
return '1'
|
return '1'
|
||||||
|
|
||||||
|
|
||||||
@admin_teams.route('/admin/teams/<int:teamid>/awards', methods=['GET'])
|
@admin_teams.route('/admin/teams/<int:teamid>/awards', methods=['GET'])
|
||||||
@admins_only
|
@admins_only
|
||||||
def admin_awards(teamid):
|
def admin_awards(teamid):
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from CTFd import utils
|
|||||||
|
|
||||||
challenges = Blueprint('challenges', __name__)
|
challenges = Blueprint('challenges', __name__)
|
||||||
|
|
||||||
|
|
||||||
@challenges.route('/hints/<int:hintid>', methods=['GET', 'POST'])
|
@challenges.route('/hints/<int:hintid>', methods=['GET', 'POST'])
|
||||||
def hints_view(hintid):
|
def hints_view(hintid):
|
||||||
hint = Hints.query.filter_by(id=hintid).first_or_404()
|
hint = Hints.query.filter_by(id=hintid).first_or_404()
|
||||||
@@ -104,9 +105,9 @@ def chals():
|
|||||||
hints = []
|
hints = []
|
||||||
for hint in Hints.query.filter_by(chal=x.id).all():
|
for hint in Hints.query.filter_by(chal=x.id).all():
|
||||||
if hint.id in unlocked_hints:
|
if hint.id in unlocked_hints:
|
||||||
hints.append({'id':hint.id, 'cost':hint.cost, 'hint':hint.hint})
|
hints.append({'id': hint.id, 'cost': hint.cost, 'hint': hint.hint})
|
||||||
else:
|
else:
|
||||||
hints.append({'id':hint.id, 'cost':hint.cost})
|
hints.append({'id': hint.id, 'cost': hint.cost})
|
||||||
# hints = [{'id':hint.id, 'cost':hint.cost} for hint in Hints.query.filter_by(chal=x.id).all()]
|
# hints = [{'id':hint.id, 'cost':hint.cost} for hint in Hints.query.filter_by(chal=x.id).all()]
|
||||||
chal_type = get_chal_class(x.type)
|
chal_type = get_chal_class(x.type)
|
||||||
json['game'].append({
|
json['game'].append({
|
||||||
@@ -293,7 +294,7 @@ def chal(chalid):
|
|||||||
logger.info("[{0}] {1} submitted {2} with kpm {3} [WRONG]".format(*data))
|
logger.info("[{0}] {1} submitted {2} with kpm {3} [WRONG]".format(*data))
|
||||||
# return '0' # key was wrong
|
# return '0' # key was wrong
|
||||||
if max_tries:
|
if max_tries:
|
||||||
attempts_left = max_tries - fails - 1 ## Off by one since fails has changed since it was gotten
|
attempts_left = max_tries - fails - 1 # Off by one since fails has changed since it was gotten
|
||||||
tries_str = 'tries'
|
tries_str = 'tries'
|
||||||
if attempts_left == 1:
|
if attempts_left == 1:
|
||||||
tries_str = 'try'
|
tries_str = 'try'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
##### GENERATE SECRET KEY #####
|
''' GENERATE SECRET KEY '''
|
||||||
|
|
||||||
with open('.ctfd_secret_key', 'a+b') as secret:
|
with open('.ctfd_secret_key', 'a+b') as secret:
|
||||||
secret.seek(0) # Seek to beginning of file since a+ mode leaves you at the end and w+ deletes the file
|
secret.seek(0) # Seek to beginning of file since a+ mode leaves you at the end and w+ deletes the file
|
||||||
@@ -10,7 +10,8 @@ with open('.ctfd_secret_key', 'a+b') as secret:
|
|||||||
secret.write(key)
|
secret.write(key)
|
||||||
secret.flush()
|
secret.flush()
|
||||||
|
|
||||||
##### SERVER SETTINGS #####
|
''' SERVER SETTINGS '''
|
||||||
|
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
'''
|
'''
|
||||||
@@ -25,7 +26,6 @@ class Config(object):
|
|||||||
'''
|
'''
|
||||||
SECRET_KEY = os.environ.get('SECRET_KEY') or key
|
SECRET_KEY = os.environ.get('SECRET_KEY') or key
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
SQLALCHEMY_DATABASE_URI is the URI that specifies the username, password, hostname, port, and database of the server
|
SQLALCHEMY_DATABASE_URI is the URI that specifies the username, password, hostname, port, and database of the server
|
||||||
used to hold the CTFd database.
|
used to hold the CTFd database.
|
||||||
@@ -34,52 +34,44 @@ class Config(object):
|
|||||||
'''
|
'''
|
||||||
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///{}/ctfd.db'.format(os.path.dirname(os.path.abspath(__file__)))
|
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///{}/ctfd.db'.format(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
SQLALCHEMY_TRACK_MODIFICATIONS is automatically disabled to suppress warnings and save memory. You should only enable
|
SQLALCHEMY_TRACK_MODIFICATIONS is automatically disabled to suppress warnings and save memory. You should only enable
|
||||||
this if you need it.
|
this if you need it.
|
||||||
'''
|
'''
|
||||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
SESSION_TYPE is a configuration value used for Flask-Session. It is currently unused in CTFd.
|
SESSION_TYPE is a configuration value used for Flask-Session. It is currently unused in CTFd.
|
||||||
http://pythonhosted.org/Flask-Session/#configuration
|
http://pythonhosted.org/Flask-Session/#configuration
|
||||||
'''
|
'''
|
||||||
SESSION_TYPE = "filesystem"
|
SESSION_TYPE = "filesystem"
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
SESSION_FILE_DIR is a configuration value used for Flask-Session. It is currently unused in CTFd.
|
SESSION_FILE_DIR is a configuration value used for Flask-Session. It is currently unused in CTFd.
|
||||||
http://pythonhosted.org/Flask-Session/#configuration
|
http://pythonhosted.org/Flask-Session/#configuration
|
||||||
'''
|
'''
|
||||||
SESSION_FILE_DIR = "/tmp/flask_session"
|
SESSION_FILE_DIR = "/tmp/flask_session"
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
SESSION_COOKIE_HTTPONLY controls if cookies should be set with the HttpOnly flag.
|
SESSION_COOKIE_HTTPONLY controls if cookies should be set with the HttpOnly flag.
|
||||||
'''
|
'''
|
||||||
SESSION_COOKIE_HTTPONLY = True
|
SESSION_COOKIE_HTTPONLY = True
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
PERMANENT_SESSION_LIFETIME is the lifetime of a session.
|
PERMANENT_SESSION_LIFETIME is the lifetime of a session.
|
||||||
'''
|
'''
|
||||||
PERMANENT_SESSION_LIFETIME = 604800 # 7 days in seconds
|
PERMANENT_SESSION_LIFETIME = 604800 # 7 days in seconds
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
HOST specifies the hostname where the CTFd instance will exist. It is currently unused.
|
HOST specifies the hostname where the CTFd instance will exist. It is currently unused.
|
||||||
'''
|
'''
|
||||||
HOST = ".ctfd.io"
|
HOST = ".ctfd.io"
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
MAILFROM_ADDR is the email address that emails are sent from if not overridden in the configuration panel.
|
MAILFROM_ADDR is the email address that emails are sent from if not overridden in the configuration panel.
|
||||||
'''
|
'''
|
||||||
MAILFROM_ADDR = "noreply@ctfd.io"
|
MAILFROM_ADDR = "noreply@ctfd.io"
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
UPLOAD_FOLDER is the location where files are uploaded.
|
UPLOAD_FOLDER is the location where files are uploaded.
|
||||||
The default destination is the CTFd/uploads folder. If you need Amazon S3 files
|
The default destination is the CTFd/uploads folder. If you need Amazon S3 files
|
||||||
@@ -87,14 +79,12 @@ class Config(object):
|
|||||||
'''
|
'''
|
||||||
UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), 'uploads')
|
UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), 'uploads')
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
TEMPLATES_AUTO_RELOAD specifies whether Flask should check for modifications to templates and
|
TEMPLATES_AUTO_RELOAD specifies whether Flask should check for modifications to templates and
|
||||||
reload them automatically
|
reload them automatically
|
||||||
'''
|
'''
|
||||||
TEMPLATES_AUTO_RELOAD = True
|
TEMPLATES_AUTO_RELOAD = True
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
TRUSTED_PROXIES defines a set of regular expressions used for finding a user's IP address if the CTFd instance
|
TRUSTED_PROXIES defines a set of regular expressions used for finding a user's IP address if the CTFd instance
|
||||||
is behind a proxy. If you are running a CTF and users are on the same network as you, you may choose to remove
|
is behind a proxy. If you are running a CTF and users are on the same network as you, you may choose to remove
|
||||||
@@ -114,7 +104,6 @@ class Config(object):
|
|||||||
'^192\.168\.'
|
'^192\.168\.'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
CACHE_TYPE specifies how CTFd should cache configuration values. If CACHE_TYPE is set to 'redis', CTFd will make use
|
CACHE_TYPE specifies how CTFd should cache configuration values. If CACHE_TYPE is set to 'redis', CTFd will make use
|
||||||
of the REDIS_URL specified in environment variables. You can also choose to hardcode the REDIS_URL here.
|
of the REDIS_URL specified in environment variables. You can also choose to hardcode the REDIS_URL here.
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
from CTFd.plugins.keys import get_key_class
|
from CTFd.plugins.keys import get_key_class
|
||||||
from CTFd.models import db, Keys
|
from CTFd.models import db, Keys
|
||||||
|
|
||||||
|
|
||||||
class BaseChallenge(object):
|
class BaseChallenge(object):
|
||||||
id = None
|
id = None
|
||||||
name = None
|
name = None
|
||||||
|
|
||||||
|
|
||||||
class CTFdStandardChallenge(BaseChallenge):
|
class CTFdStandardChallenge(BaseChallenge):
|
||||||
id = 0
|
id = 0
|
||||||
name = "standard"
|
name = "standard"
|
||||||
@@ -19,9 +21,10 @@ class CTFdStandardChallenge(BaseChallenge):
|
|||||||
|
|
||||||
|
|
||||||
CHALLENGE_CLASSES = {
|
CHALLENGE_CLASSES = {
|
||||||
0 : CTFdStandardChallenge
|
0: CTFdStandardChallenge
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_chal_class(class_id):
|
def get_chal_class(class_id):
|
||||||
cls = CHALLENGE_CLASSES.get(class_id)
|
cls = CHALLENGE_CLASSES.get(class_id)
|
||||||
if cls is None:
|
if cls is None:
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class BaseKey(object):
|
|||||||
def compare(self, saved, provided):
|
def compare(self, saved, provided):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class CTFdStaticKey(BaseKey):
|
class CTFdStaticKey(BaseKey):
|
||||||
id = 0
|
id = 0
|
||||||
name = "static"
|
name = "static"
|
||||||
@@ -36,8 +37,8 @@ class CTFdRegexKey(BaseKey):
|
|||||||
|
|
||||||
|
|
||||||
KEY_CLASSES = {
|
KEY_CLASSES = {
|
||||||
0 : CTFdStaticKey,
|
0: CTFdStaticKey,
|
||||||
1 : CTFdRegexKey
|
1: CTFdRegexKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,6 @@ def topteams(count):
|
|||||||
solves = Solves.query.filter_by(teamid=team.teamid)
|
solves = Solves.query.filter_by(teamid=team.teamid)
|
||||||
awards = Awards.query.filter_by(teamid=team.teamid)
|
awards = Awards.query.filter_by(teamid=team.teamid)
|
||||||
|
|
||||||
|
|
||||||
freeze = utils.get_config('freeze')
|
freeze = utils.get_config('freeze')
|
||||||
|
|
||||||
if freeze:
|
if freeze:
|
||||||
@@ -112,7 +111,6 @@ def topteams(count):
|
|||||||
solves = solves.all()
|
solves = solves.all()
|
||||||
awards = awards.all()
|
awards = awards.all()
|
||||||
|
|
||||||
|
|
||||||
json['scores'][team.name] = []
|
json['scores'][team.name] = []
|
||||||
for x in solves:
|
for x in solves:
|
||||||
json['scores'][team.name].append({
|
json['scores'][team.name].append({
|
||||||
|
|||||||
@@ -226,7 +226,6 @@ def is_scoreboard_frozen():
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def ctftime():
|
def ctftime():
|
||||||
""" Checks whether it's CTF time or not. """
|
""" Checks whether it's CTF time or not. """
|
||||||
|
|
||||||
@@ -669,7 +668,7 @@ def export_ctf(segments=None):
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
## Backup database
|
# Backup database
|
||||||
backup = io.BytesIO()
|
backup = io.BytesIO()
|
||||||
backup_zip = zipfile.ZipFile(backup, 'w')
|
backup_zip = zipfile.ZipFile(backup, 'w')
|
||||||
|
|
||||||
@@ -682,7 +681,7 @@ def export_ctf(segments=None):
|
|||||||
result_file.seek(0)
|
result_file.seek(0)
|
||||||
backup_zip.writestr('db/{}.json'.format(item), result_file.read())
|
backup_zip.writestr('db/{}.json'.format(item), result_file.read())
|
||||||
|
|
||||||
## Backup uploads
|
# Backup uploads
|
||||||
upload_folder = os.path.join(os.path.normpath(app.root_path), get_config('UPLOAD_FOLDER'))
|
upload_folder = os.path.join(os.path.normpath(app.root_path), get_config('UPLOAD_FOLDER'))
|
||||||
for root, dirs, files in os.walk(upload_folder):
|
for root, dirs, files in os.walk(upload_folder):
|
||||||
for file in files:
|
for file in files:
|
||||||
@@ -730,7 +729,7 @@ def import_ctf(backup, segments=None, erase=False):
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
## Need special handling of metadata
|
# Need special handling of metadata
|
||||||
if 'metadata' in segments:
|
if 'metadata' in segments:
|
||||||
meta = groups['metadata']
|
meta = groups['metadata']
|
||||||
segments.remove('metadata')
|
segments.remove('metadata')
|
||||||
@@ -741,7 +740,7 @@ def import_ctf(backup, segments=None, erase=False):
|
|||||||
path = "db/{}.json".format(item)
|
path = "db/{}.json".format(item)
|
||||||
data = backup.open(path).read()
|
data = backup.open(path).read()
|
||||||
|
|
||||||
## Some JSON files will be empty
|
# Some JSON files will be empty
|
||||||
if data:
|
if data:
|
||||||
if item == 'config':
|
if item == 'config':
|
||||||
saved = json.loads(data)
|
saved = json.loads(data)
|
||||||
@@ -776,7 +775,6 @@ def import_ctf(backup, segments=None, erase=False):
|
|||||||
db.session.add(container)
|
db.session.add(container)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
for segment in segments:
|
for segment in segments:
|
||||||
group = groups[segment]
|
group = groups[segment]
|
||||||
for item in group:
|
for item in group:
|
||||||
@@ -791,20 +789,20 @@ def import_ctf(backup, segments=None, erase=False):
|
|||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
## Extracting files
|
# Extracting files
|
||||||
files = [f for f in backup.namelist() if f.startswith('uploads/')]
|
files = [f for f in backup.namelist() if f.startswith('uploads/')]
|
||||||
upload_folder = app.config.get('UPLOAD_FOLDER')
|
upload_folder = app.config.get('UPLOAD_FOLDER')
|
||||||
for f in files:
|
for f in files:
|
||||||
filename = f.split(os.sep, 1)
|
filename = f.split(os.sep, 1)
|
||||||
|
|
||||||
if len(filename) < 2: ## just an empty uploads directory (e.g. uploads/)
|
if len(filename) < 2: # just an empty uploads directory (e.g. uploads/)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
filename = filename[1] ## Get the second entry in the list (the actual filename)
|
filename = filename[1] # Get the second entry in the list (the actual filename)
|
||||||
full_path = os.path.join(upload_folder, filename)
|
full_path = os.path.join(upload_folder, filename)
|
||||||
dirname = os.path.dirname(full_path)
|
dirname = os.path.dirname(full_path)
|
||||||
|
|
||||||
## Create any parent directories for the file
|
# Create any parent directories for the file
|
||||||
if not os.path.exists(dirname):
|
if not os.path.exists(dirname):
|
||||||
os.makedirs(dirname)
|
os.makedirs(dirname)
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ def setup():
|
|||||||
|
|
||||||
# Index page
|
# Index page
|
||||||
page = Pages('index', """<div class="container main-container">
|
page = Pages('index', """<div class="container main-container">
|
||||||
<img class="logo" src="{0}/static/original/img/logo.png" />
|
<img class="logo" src="static/original/img/logo.png" />
|
||||||
<h3 class="text-center">
|
<h3 class="text-center">
|
||||||
<p>A cool CTF platform from <a href="https://ctfd.io">ctfd.io</a></p>
|
<p>A cool CTF platform from <a href="https://ctfd.io">ctfd.io</a></p>
|
||||||
<p>Follow us on social media:</p>
|
<p>Follow us on social media:</p>
|
||||||
@@ -55,7 +55,7 @@ def setup():
|
|||||||
</h3>
|
</h3>
|
||||||
<br>
|
<br>
|
||||||
<h4 class="text-center">
|
<h4 class="text-center">
|
||||||
<a href="{0}/admin">Click here</a> to login and setup your CTF
|
<a href="admin">Click here</a> to login and setup your CTF
|
||||||
</h4>
|
</h4>
|
||||||
</div>""".format(request.script_root))
|
</div>""".format(request.script_root))
|
||||||
|
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ coverage>=4.1
|
|||||||
mock>=2.0.0
|
mock>=2.0.0
|
||||||
nose>=1.3.7
|
nose>=1.3.7
|
||||||
rednose>=1.1.1
|
rednose>=1.1.1
|
||||||
|
pep8==1.7.0
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ def gen_solve(db, chalid, teamid, ip='127.0.0.1', flag='rightkey'):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
return solve
|
return solve
|
||||||
|
|
||||||
|
|
||||||
def gen_wrongkey(db, teamid, chalid, flag='wrongkey'):
|
def gen_wrongkey(db, teamid, chalid, flag='wrongkey'):
|
||||||
wrongkey = WrongKeys(teamid, chalid, flag)
|
wrongkey = WrongKeys(teamid, chalid, flag)
|
||||||
db.session.add(wrongkey)
|
db.session.add(wrongkey)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ def test_register_user():
|
|||||||
|
|
||||||
|
|
||||||
def test_register_duplicate_teamname():
|
def test_register_duplicate_teamname():
|
||||||
"""A user shouldn't be able to use and already registered team name"""
|
"""A user shouldn't be able to use an already registered team name"""
|
||||||
app = create_ctfd()
|
app = create_ctfd()
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
register_user(app, name="user1", email="user1@ctfd.io", password="password")
|
register_user(app, name="user1", email="user1@ctfd.io", password="password")
|
||||||
@@ -74,7 +74,7 @@ def test_user_isnt_admin():
|
|||||||
|
|
||||||
|
|
||||||
def test_user_get_teams():
|
def test_user_get_teams():
|
||||||
"""Can a registered user can load /teams"""
|
"""Can a registered user load /teams"""
|
||||||
app = create_ctfd()
|
app = create_ctfd()
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
register_user(app)
|
register_user(app)
|
||||||
@@ -84,7 +84,7 @@ def test_user_get_teams():
|
|||||||
|
|
||||||
|
|
||||||
def test_user_get_scoreboard():
|
def test_user_get_scoreboard():
|
||||||
"""Can a registered user can load /scoreboard"""
|
"""Can a registered user load /scoreboard"""
|
||||||
app = create_ctfd()
|
app = create_ctfd()
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
register_user(app)
|
register_user(app)
|
||||||
@@ -94,7 +94,7 @@ def test_user_get_scoreboard():
|
|||||||
|
|
||||||
|
|
||||||
def test_user_get_scores():
|
def test_user_get_scores():
|
||||||
"""Can a registered user can load /scores"""
|
"""Can a registered user load /scores"""
|
||||||
app = create_ctfd()
|
app = create_ctfd()
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
register_user(app)
|
register_user(app)
|
||||||
@@ -104,7 +104,7 @@ def test_user_get_scores():
|
|||||||
|
|
||||||
|
|
||||||
def test_user_get_topteams():
|
def test_user_get_topteams():
|
||||||
"""Can a registered user can load /top/10"""
|
"""Can a registered user load /top/10"""
|
||||||
app = create_ctfd()
|
app = create_ctfd()
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
register_user(app)
|
register_user(app)
|
||||||
@@ -114,7 +114,7 @@ def test_user_get_topteams():
|
|||||||
|
|
||||||
|
|
||||||
def test_user_get_challenges():
|
def test_user_get_challenges():
|
||||||
"""Can a registered user can load /challenges"""
|
"""Can a registered user load /challenges"""
|
||||||
app = create_ctfd()
|
app = create_ctfd()
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
register_user(app)
|
register_user(app)
|
||||||
@@ -124,7 +124,7 @@ def test_user_get_challenges():
|
|||||||
|
|
||||||
|
|
||||||
def test_user_get_chals():
|
def test_user_get_chals():
|
||||||
"""Can a registered user can load /chals"""
|
"""Can a registered user load /chals"""
|
||||||
app = create_ctfd()
|
app = create_ctfd()
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
register_user(app)
|
register_user(app)
|
||||||
@@ -134,7 +134,7 @@ def test_user_get_chals():
|
|||||||
|
|
||||||
|
|
||||||
def test_user_get_solves_per_chal():
|
def test_user_get_solves_per_chal():
|
||||||
"""Can a registered user can load /chals/solves"""
|
"""Can a registered user load /chals/solves"""
|
||||||
app = create_ctfd()
|
app = create_ctfd()
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
register_user(app)
|
register_user(app)
|
||||||
@@ -144,7 +144,7 @@ def test_user_get_solves_per_chal():
|
|||||||
|
|
||||||
|
|
||||||
def test_user_get_solves():
|
def test_user_get_solves():
|
||||||
"""Can a registered user can load /solves"""
|
"""Can a registered user load /solves"""
|
||||||
app = create_ctfd()
|
app = create_ctfd()
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
register_user(app)
|
register_user(app)
|
||||||
@@ -154,7 +154,7 @@ def test_user_get_solves():
|
|||||||
|
|
||||||
|
|
||||||
def test_user_get_team_page():
|
def test_user_get_team_page():
|
||||||
"""Can a registered user can load their public profile (/team/2)"""
|
"""Can a registered user load their public profile (/team/2)"""
|
||||||
app = create_ctfd()
|
app = create_ctfd()
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
register_user(app)
|
register_user(app)
|
||||||
@@ -164,7 +164,7 @@ def test_user_get_team_page():
|
|||||||
|
|
||||||
|
|
||||||
def test_user_get_profile():
|
def test_user_get_profile():
|
||||||
"""Can a registered user can load their private profile (/profile)"""
|
"""Can a registered user load their private profile (/profile)"""
|
||||||
app = create_ctfd()
|
app = create_ctfd()
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
register_user(app)
|
register_user(app)
|
||||||
|
|||||||
Reference in New Issue
Block a user