Skip to content

Commit

Permalink
Merge tag '3.6.0'
Browse files Browse the repository at this point in the history
# Conflicts:
#	CTFd/plugins/dynamic_challenges/__init__.py
#	CTFd/themes/admin/templates/configs/settings.html
#	CTFd/utils/uploads/uploaders.py
  • Loading branch information
hakatashi committed Oct 20, 2023
2 parents 7dc88e5 + af5e88d commit 27d3572
Show file tree
Hide file tree
Showing 277 changed files with 13,443 additions and 850 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r development.txt
python -m pip install -r linting.txt
sudo yarn install --non-interactive
sudo yarn global add [email protected]
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ nosetests.xml
coverage.xml

# Translations
*.mo
*.pot
# TODO: CTFd 4.0 We should consider generating .mo files in a Docker image instead of saving them in git
# *.mo

# Django stuff:
*.log
Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
CTFd/themes/**/vendor/
CTFd/themes/core-beta/**/*
*.html
*.njk
*.png
Expand Down
79 changes: 79 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,82 @@
# 3.6.0 / 2023-08-21

**General**

- Translations support for Spanish, Polish, German, Chinese
- If you wish to fix or maintain a language translation please join at CTFd's public [POEditor page](https://poeditor.com/join/project/p5jhdcrlm7).
- Add a total user registration limit option
- Dynamic value challenges can now choose between linear and logarithmic decay functions
- Free hints are now visible by unauthenticated users if challenges are visible by unauthenticated users
- Fix issue where a custom field named affiliation or website prevented registration
- No longer special case "Affiliation" or "Website" as custom field titles. Previously custom fields with those titles would set the user's affiliation or website but this behavior has been removed.

**Admin Panel**

- Challenge Preview has been improved to support arbitrary custom themes
- Long flags in the Admin Panel are now truncated but can be expanded and copied
- Add UI to mark incorrect submissions as correct
- Add the `discard` type for submissions
- Add `PATCH /api/v1/submissions/[submission_id]` to mark submissions as correct
- Add section in the Config Panel to configure `HTML_SANITIZATION`
- Setting `HTML_SANITIZATION` to true in `config.ini` cannot be disabled via the Admin Panel
- Add wildcard for email whitelisting

**Deployment**

- Add new envvar `SKIP_DB_PING` to instruct the CTFd Docker image to not test if the database server is available
- Add new config `AWS_S3_ADDRESSING_STYLE`
- Support selecting the [S3 addressing style](https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-bucket-intro.html#access-bucket-console-ex). It defaults to "auto" as when it's not set, but can also be set to `virtual` or `path`
- Add new config `AWS_S3_CUSTOM_DOMAIN` which specifies a domain that replaces the default one in presigned download URLs
- Required for certain S3 implementations
- Flask and Werkzeug have been upgraded to v2.0.3. Other dependencies have been updated for compatability.
- SQLAlchemy has been updated to v1.4.
- PyMySQL has been upgraded to v1.0.2.
- The `flask` cli tool is now offered as an alternative to the `manage.py` script.
- gzip compression is now enabled in the provided nginx configuration

**API**

- API tokens now have a description field
- API tokens now start with a `ctfd_` prefix to make them easier to identify
- `GET /api/v1/hints/[hint_id]` will now return hint information for free hints for unauthenticated users if challenges are visible

**Themes**

- core-beta is now provided in all CTFd instances
- core-beta is the default theme during setup

# 3.5.3 / 2023-06-08

**Deployment**

- Fixed permissions error in Dockerfile
- Bump dependencies for pybluemonday

# 3.5.2 / 2023-05-01

**General**

- Generate cachable S3 URLs by rounding time down to the previous hour to generate a consistent URL
- Change email whitelist error message to not include the list of allowed domains
- Clean up the language for confirming the password on team password change
- Fix issue where dynamic challenges break if the decay is 0 and prevent users from adding a decay limit of 0 to dynamic value challenges

**Admin Panel**

- Adds support for admins to control `robots.txt`
- Clean up the aesthetics for the 'Pause CTF' and 'View After CTF' configs
- Replaced TLS and SSL checkbox text to match the defaults used by Mozilla Thunderbird to eliminate confusion when configuring SMTP

**Deployment**

- Slim down Docker image by removing several dependencies not needed for production usage
- The image size has been reduced from 648MB to 398MB
- In the Docker image run CTFd in a virtual environment located at `/opt/venv`
- Add freezegun to application dependencies
- Bump dependencies for pybluemonday, redis, SQLAlchemy-Utils, python-geoacumen-city
- Fix race conditions on cache healthcheck
- Fix situations where numeric config items in config.ini could cause CTFd to not start

# 3.5.1 / 2023-01-23

**General**
Expand Down
63 changes: 37 additions & 26 deletions CTFd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,20 @@

import jinja2
from flask import Flask, Request
from flask.helpers import safe_join
from flask_babel import Babel
from flask_migrate import upgrade
from jinja2 import FileSystemLoader
from jinja2.sandbox import SandboxedEnvironment
from werkzeug.middleware.proxy_fix import ProxyFix
from werkzeug.utils import cached_property
from werkzeug.utils import safe_join

import CTFd.utils.config
from CTFd import utils
from CTFd.constants.themes import ADMIN_THEME, DEFAULT_THEME
from CTFd.plugins import init_plugins
from CTFd.utils.crypto import sha256
from CTFd.utils.initialization import (
init_cli,
init_events,
init_logs,
init_request_processors,
Expand All @@ -28,22 +29,21 @@
from CTFd.utils.migrations import create_database, migrations, stamp_latest_revision
from CTFd.utils.sessions import CachingSessionInterface
from CTFd.utils.updates import update_check
from CTFd.utils.user import get_locale

__version__ = "3.5.1"
__version__ = "3.6.0"
__channel__ = "oss"


class CTFdRequest(Request):
@cached_property
def path(self):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
"""
Hijack the original Flask request path because it does not account for subdirectory deployments in an intuitive
manner. We append script_root so that the path always points to the full path as seen in the browser.
e.g. /subdirectory/path/route vs /path/route
:return: string
"""
return self.script_root + super(CTFdRequest, self).path
self.path = self.script_root + self.path


class CTFdFlask(Flask):
Expand Down Expand Up @@ -84,24 +84,30 @@ def _load_template(self, name, globals):
theme = str(utils.get_config("ctf_theme"))
cache_name = theme + "/" + name

# Rest of this code is copied from Jinja
# https://github.com/pallets/jinja/blob/master/src/jinja2/environment.py#L802-L815
# Rest of this code roughly copied from Jinja
# https://github.com/pallets/jinja/blob/b08cd4bc64bb980df86ed2876978ae5735572280/src/jinja2/environment.py#L956-L973
cache_key = (weakref.ref(self.loader), cache_name)
if self.cache is not None:
template = self.cache.get(cache_key)
if template is not None and (
not self.auto_reload or template.is_up_to_date
):
# template.globals is a ChainMap, modifying it will only
# affect the template, not the environment globals.
if globals:
template.globals.update(globals)

return template
template = self.loader.load(self, name, globals)

template = self.loader.load(self, name, self.make_globals(globals))

if self.cache is not None:
self.cache[cache_key] = template
return template


class ThemeLoader(FileSystemLoader):
"""Custom FileSystemLoader that is aware of theme structure and config.
"""
"""Custom FileSystemLoader that is aware of theme structure and config."""

DEFAULT_THEMES_PATH = os.path.join(os.path.dirname(__file__), "themes")
_ADMIN_THEME_PREFIX = ADMIN_THEME + "/"
Expand Down Expand Up @@ -185,15 +191,15 @@ def create_app(config="CTFd.config.Config"):
app.jinja_loader = jinja2.ChoiceLoader(loaders)

from CTFd.models import ( # noqa: F401
db,
Teams,
Solves,
Challenges,
Fails,
Files,
Flags,
Solves,
Tags,
Files,
Teams,
Tracking,
db,
)

url = create_database()
Expand All @@ -208,14 +214,18 @@ def create_app(config="CTFd.config.Config"):
# Register Flask-Migrate
migrations.init_app(app, db)

babel = Babel()
babel.locale_selector_func = get_locale
babel.init_app(app)

# Alembic sqlite support is lacking so we should just create_all anyway
if url.drivername.startswith("sqlite"):
# Enable foreign keys for SQLite. This must be before the
# db.create_all call because tests use the in-memory SQLite
# database (each connection, including db creation, is a new db).
# https://docs.sqlalchemy.org/en/13/dialects/sqlite.html#foreign-key-support
from sqlalchemy.engine import Engine
from sqlalchemy import event
from sqlalchemy.engine import Engine

@event.listens_for(Engine, "connect")
def set_sqlite_pragma(dbapi_connection, connection_record):
Expand Down Expand Up @@ -266,7 +276,7 @@ def set_sqlite_pragma(dbapi_connection, connection_record):
utils.set_config("ctf_version", __version__)

if not utils.get_config("ctf_theme"):
utils.set_config("ctf_theme", DEFAULT_THEME)
utils.set_config("ctf_theme", "core-beta")

update_check(force=True)

Expand All @@ -275,16 +285,16 @@ def set_sqlite_pragma(dbapi_connection, connection_record):
init_template_globals(app)

# Importing here allows tests to use sensible names (e.g. api instead of api_bp)
from CTFd.views import views
from CTFd.teams import teams
from CTFd.users import users
from CTFd.challenges import challenges
from CTFd.scoreboard import scoreboard
from CTFd.auth import auth
from CTFd.admin import admin
from CTFd.api import api
from CTFd.events import events
from CTFd.auth import auth
from CTFd.challenges import challenges
from CTFd.errors import render_error
from CTFd.events import events
from CTFd.scoreboard import scoreboard
from CTFd.teams import teams
from CTFd.users import users
from CTFd.views import views

app.register_blueprint(views)
app.register_blueprint(teams)
Expand All @@ -303,5 +313,6 @@ def set_sqlite_pragma(dbapi_connection, connection_record):
init_logs(app)
init_events(app)
init_plugins(app)
init_cli(app)

return app
35 changes: 21 additions & 14 deletions CTFd/admin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import csv
import csv # noqa: I001
import datetime
import os
from io import StringIO
Expand All @@ -18,14 +18,14 @@
admin = Blueprint("admin", __name__)

# isort:imports-firstparty
from CTFd.admin import challenges # noqa: F401
from CTFd.admin import notifications # noqa: F401
from CTFd.admin import pages # noqa: F401
from CTFd.admin import scoreboard # noqa: F401
from CTFd.admin import statistics # noqa: F401
from CTFd.admin import submissions # noqa: F401
from CTFd.admin import teams # noqa: F401
from CTFd.admin import users # noqa: F401
from CTFd.admin import challenges # noqa: F401,I001
from CTFd.admin import notifications # noqa: F401,I001
from CTFd.admin import pages # noqa: F401,I001
from CTFd.admin import scoreboard # noqa: F401,I001
from CTFd.admin import statistics # noqa: F401,I001
from CTFd.admin import submissions # noqa: F401,I001
from CTFd.admin import teams # noqa: F401,I001
from CTFd.admin import users # noqa: F401,I001
from CTFd.cache import (
cache,
clear_challenges,
Expand All @@ -48,7 +48,7 @@
db,
)
from CTFd.utils import config as ctf_config
from CTFd.utils import get_config, set_config
from CTFd.utils import get_app_config, get_config, set_config
from CTFd.utils.csv import dump_csv, load_challenges_csv, load_teams_csv, load_users_csv
from CTFd.utils.decorators import admins_only
from CTFd.utils.exports import background_import_ctf
Expand Down Expand Up @@ -120,7 +120,7 @@ def export_ctf():
backup = export_ctf_util()
ctf_name = ctf_config.ctf_name()
day = datetime.datetime.now().strftime("%Y-%m-%d_%T")
full_name = u"{}.{}.zip".format(ctf_name, day)
full_name = "{}.{}.zip".format(ctf_name, day)
return send_file(
backup, cache_timeout=-1, as_attachment=True, attachment_filename=full_name
)
Expand Down Expand Up @@ -166,8 +166,8 @@ def export_csv():
return send_file(
output,
as_attachment=True,
cache_timeout=-1,
attachment_filename="{name}-{table}.csv".format(
max_age=-1,
download_name="{name}-{table}.csv".format(
name=ctf_config.ctf_name(), table=table
),
)
Expand All @@ -190,7 +190,14 @@ def config():
except ValueError:
pass

return render_template("admin/config.html", themes=themes, **configs)
force_html_sanitization = get_app_config("HTML_SANITIZATION")

return render_template(
"admin/config.html",
themes=themes,
**configs,
force_html_sanitization=force_html_sanitization
)


@admin.route("/admin/reset", methods=["GET", "POST"])
Expand Down
Loading

0 comments on commit 27d3572

Please sign in to comment.