mirror of
https://github.com/aljazceru/CTFd.git
synced 2025-12-18 06:24:23 +01:00
2.3.0 / 2020-02-17
==================
**General**
* During setup, admins can register their email address with the CTFd LLC newsletter for news and updates
* Fix editting hints from the admin panel
* Allow admins to insert HTML code directly into the header and footer (end of body tag) of pages. This replaces and supercedes the custom CSS feature.
* The `views.custom_css` route has been removed.
* Admins can now customize the content of outgoing emails and inject certain variables into email content.
* The `manage.py` script can now manipulate the CTFd Configs table via the `get_config` and `set_config` commands. (e.g. `python manage.py get_config ctf_theme` and `python manage.py set_config ctf_theme core`)
**Themes**
* Themes should now reference the `theme_header` and `theme_footer` configs instead of the `views.custom_css` endpoint to allow for user customizations. See the `base.html` file of the core theme.
**Plugins**
* Make `ezq` functions available to `CTFd.js` under `CTFd.ui.ezq`
**Miscellaneous**
* Python imports sorted with `isort` and import order enforced
* Black formatter running on a majority of Python code
193 lines
5.9 KiB
Python
193 lines
5.9 KiB
Python
import glob
|
|
import importlib
|
|
import os
|
|
from collections import namedtuple
|
|
|
|
from flask import current_app as app
|
|
from flask import send_file, send_from_directory
|
|
|
|
from CTFd.utils.config.pages import get_pages
|
|
from CTFd.utils.decorators import admins_only as admins_only_wrapper
|
|
from CTFd.utils.plugins import override_template as utils_override_template
|
|
from CTFd.utils.plugins import (
|
|
register_admin_script as utils_register_admin_plugin_script,
|
|
)
|
|
from CTFd.utils.plugins import (
|
|
register_admin_stylesheet as utils_register_admin_plugin_stylesheet,
|
|
)
|
|
from CTFd.utils.plugins import register_script as utils_register_plugin_script
|
|
from CTFd.utils.plugins import register_stylesheet as utils_register_plugin_stylesheet
|
|
|
|
Menu = namedtuple("Menu", ["title", "route"])
|
|
|
|
|
|
def register_plugin_assets_directory(app, base_path, admins_only=False, endpoint=None):
|
|
"""
|
|
Registers a directory to serve assets
|
|
|
|
:param app: A CTFd application
|
|
:param string base_path: The path to the directory
|
|
:param boolean admins_only: Whether or not the assets served out of the directory should be accessible to the public
|
|
:return:
|
|
"""
|
|
base_path = base_path.strip("/")
|
|
if endpoint is None:
|
|
endpoint = base_path.replace("/", ".")
|
|
|
|
def assets_handler(path):
|
|
return send_from_directory(base_path, path)
|
|
|
|
rule = "/" + base_path + "/<path:path>"
|
|
app.add_url_rule(rule=rule, endpoint=endpoint, view_func=assets_handler)
|
|
|
|
|
|
def register_plugin_asset(app, asset_path, admins_only=False, endpoint=None):
|
|
"""
|
|
Registers an file path to be served by CTFd
|
|
|
|
:param app: A CTFd application
|
|
:param string asset_path: The path to the asset file
|
|
:param boolean admins_only: Whether or not this file should be accessible to the public
|
|
:return:
|
|
"""
|
|
asset_path = asset_path.strip("/")
|
|
if endpoint is None:
|
|
endpoint = asset_path.replace("/", ".")
|
|
|
|
def asset_handler():
|
|
return send_file(asset_path)
|
|
|
|
if admins_only:
|
|
asset_handler = admins_only_wrapper(asset_handler)
|
|
rule = "/" + asset_path
|
|
app.add_url_rule(rule=rule, endpoint=endpoint, view_func=asset_handler)
|
|
|
|
|
|
def override_template(*args, **kwargs):
|
|
"""
|
|
Overrides a template with the provided html content.
|
|
|
|
e.g. override_template('scoreboard.html', '<h1>scores</h1>')
|
|
"""
|
|
utils_override_template(*args, **kwargs)
|
|
|
|
|
|
def register_plugin_script(*args, **kwargs):
|
|
"""
|
|
Adds a given script to the base.html template which all pages inherit from
|
|
"""
|
|
utils_register_plugin_script(*args, **kwargs)
|
|
|
|
|
|
def register_plugin_stylesheet(*args, **kwargs):
|
|
"""
|
|
Adds a given stylesheet to the base.html template which all pages inherit from.
|
|
"""
|
|
utils_register_plugin_stylesheet(*args, **kwargs)
|
|
|
|
|
|
def register_admin_plugin_script(*args, **kwargs):
|
|
"""
|
|
Adds a given script to the base.html of the admin theme which all admin pages inherit from
|
|
:param args:
|
|
:param kwargs:
|
|
:return:
|
|
"""
|
|
utils_register_admin_plugin_script(*args, **kwargs)
|
|
|
|
|
|
def register_admin_plugin_stylesheet(*args, **kwargs):
|
|
"""
|
|
Adds a given stylesheet to the base.html of the admin theme which all admin pages inherit from
|
|
:param args:
|
|
:param kwargs:
|
|
:return:
|
|
"""
|
|
utils_register_admin_plugin_stylesheet(*args, **kwargs)
|
|
|
|
|
|
def register_admin_plugin_menu_bar(title, route):
|
|
"""
|
|
Registers links on the Admin Panel menubar/navbar
|
|
|
|
:param name: A string that is shown on the navbar HTML
|
|
:param route: A string that is the href used by the link
|
|
:return:
|
|
"""
|
|
am = Menu(title=title, route=route)
|
|
app.admin_plugin_menu_bar.append(am)
|
|
|
|
|
|
def get_admin_plugin_menu_bar():
|
|
"""
|
|
Access the list used to store the plugin menu bar
|
|
|
|
:return: Returns a list of Menu namedtuples. They have name, and route attributes.
|
|
"""
|
|
return app.admin_plugin_menu_bar
|
|
|
|
|
|
def register_user_page_menu_bar(title, route):
|
|
"""
|
|
Registers links on the User side menubar/navbar
|
|
|
|
:param name: A string that is shown on the navbar HTML
|
|
:param route: A string that is the href used by the link
|
|
:return:
|
|
"""
|
|
p = Menu(title=title, route=route)
|
|
app.plugin_menu_bar.append(p)
|
|
|
|
|
|
def get_user_page_menu_bar():
|
|
"""
|
|
Access the list used to store the user page menu bar
|
|
|
|
:return: Returns a list of Menu namedtuples. They have name, and route attributes.
|
|
"""
|
|
return get_pages() + app.plugin_menu_bar
|
|
|
|
|
|
def bypass_csrf_protection(f):
|
|
"""
|
|
Decorator that allows a route to bypass the need for a CSRF nonce on POST requests.
|
|
|
|
This should be considered beta and may change in future versions.
|
|
|
|
:param f: A function that needs to bypass CSRF protection
|
|
:return: Returns a function with the _bypass_csrf attribute set which tells CTFd to not require CSRF protection.
|
|
"""
|
|
f._bypass_csrf = True
|
|
return f
|
|
|
|
|
|
def init_plugins(app):
|
|
"""
|
|
Searches for the load function in modules in the CTFd/plugins folder. This function is called with the current CTFd
|
|
app as a parameter. This allows CTFd plugins to modify CTFd's behavior.
|
|
|
|
:param app: A CTFd application
|
|
:return:
|
|
"""
|
|
app.admin_plugin_scripts = []
|
|
app.admin_plugin_stylesheets = []
|
|
app.plugin_scripts = []
|
|
app.plugin_stylesheets = []
|
|
|
|
app.admin_plugin_menu_bar = []
|
|
app.plugin_menu_bar = []
|
|
|
|
if app.config.get("SAFE_MODE", False) is False:
|
|
modules = sorted(glob.glob(os.path.dirname(__file__) + "/*"))
|
|
blacklist = {"__pycache__"}
|
|
for module in modules:
|
|
module_name = os.path.basename(module)
|
|
if os.path.isdir(module) and module_name not in blacklist:
|
|
module = "." + module_name
|
|
module = importlib.import_module(module, package="CTFd.plugins")
|
|
module.load(app)
|
|
print(" * Loaded module, %s" % module)
|
|
|
|
app.jinja_env.globals.update(get_admin_plugin_menu_bar=get_admin_plugin_menu_bar)
|
|
app.jinja_env.globals.update(get_user_page_menu_bar=get_user_page_menu_bar)
|