WIP: Add form globals (#1469)

* Work on #1467 
* Creates the Form global which will contain all forms.
This commit is contained in:
Kevin Chung
2020-06-11 02:32:20 -04:00
committed by GitHub
parent 62b5d4fc4e
commit a47cdb7ce1
51 changed files with 976 additions and 654 deletions

View File

@@ -163,17 +163,13 @@ def config():
# Clear the config cache so that we don't get stale values
clear_config()
database_tables = sorted(db.metadata.tables.keys())
configs = Configs.query.all()
configs = dict([(c.key, get_config(c.key)) for c in configs])
themes = ctf_config.get_themes()
themes.remove(get_config("ctf_theme"))
return render_template(
"admin/config.html", database_tables=database_tables, themes=themes, **configs
)
return render_template("admin/config.html", themes=themes, **configs)
@admin.route("/admin/reset", methods=["GET", "POST"])

View File

@@ -17,7 +17,7 @@ from CTFd.utils.config.visibility import registration_visible
from CTFd.utils.crypto import verify_password
from CTFd.utils.decorators import ratelimit
from CTFd.utils.decorators.visibility import check_registration_visibility
from CTFd.utils.helpers import error_for, get_errors
from CTFd.utils.helpers import error_for, get_errors, markup
from CTFd.utils.logging import log
from CTFd.utils.modes import TEAMS_MODE
from CTFd.utils.security.auth import login_user, logout_user
@@ -93,6 +93,16 @@ def confirm(data=None):
@auth.route("/reset_password/<data>", methods=["POST", "GET"])
@ratelimit(method="POST", limit=10, interval=60)
def reset_password(data=None):
if config.can_send_mail() is False:
return render_template(
"reset_password.html",
errors=[
markup(
"This CTF is not configured to send email.<br> Please contact an organizer to have your password reset."
)
],
)
if data is not None:
try:
email_address = unserialize(data, max_age=1800)
@@ -142,12 +152,6 @@ def reset_password(data=None):
get_errors()
if config.can_send_mail() is False:
return render_template(
"reset_password.html",
errors=["Email could not be sent due to server misconfiguration"],
)
if not user:
return render_template(
"reset_password.html",

View File

@@ -6,6 +6,10 @@ class _ConfigsWrapper:
def __getattr__(self, attr):
return get_config(attr)
@property
def ctf_name(self):
return get_config("theme_header", default="CTFd")
@property
def theme_header(self):
return markup(get_config("theme_header", default=""))

49
CTFd/forms/__init__.py Normal file
View File

@@ -0,0 +1,49 @@
from wtforms import Form
from wtforms.csrf.core import CSRF
class CTFdCSRF(CSRF):
def generate_csrf_token(self, csrf_token_field):
from flask import session
return session.get("nonce")
class BaseForm(Form):
class Meta:
csrf = True
csrf_class = CTFdCSRF
csrf_field_name = "nonce"
class _FormsWrapper:
pass
Forms = _FormsWrapper()
from CTFd.forms import auth # noqa: I001 isort:skip
from CTFd.forms import self # noqa: I001 isort:skip
from CTFd.forms import teams # noqa: I001 isort:skip
from CTFd.forms import setup # noqa: I001 isort:skip
from CTFd.forms import submissions # noqa: I001 isort:skip
from CTFd.forms import users # noqa: I001 isort:skip
from CTFd.forms import challenges # noqa: I001 isort:skip
from CTFd.forms import notifications # noqa: I001 isort:skip
from CTFd.forms import config # noqa: I001 isort:skip
from CTFd.forms import pages # noqa: I001 isort:skip
from CTFd.forms import awards # noqa: I001 isort:skip
from CTFd.forms import email # noqa: I001 isort:skip
Forms.auth = auth
Forms.self = self
Forms.teams = teams
Forms.setup = setup
Forms.submissions = submissions
Forms.users = users
Forms.challenges = challenges
Forms.notifications = notifications
Forms.config = config
Forms.pages = pages
Forms.awards = awards
Forms.email = email

33
CTFd/forms/auth.py Normal file
View File

@@ -0,0 +1,33 @@
from wtforms import PasswordField, StringField
from wtforms.fields.html5 import EmailField
from wtforms.validators import InputRequired
from CTFd.forms import BaseForm
from CTFd.forms.fields import SubmitField
class RegistrationForm(BaseForm):
name = StringField("User Name", validators=[InputRequired()])
email = EmailField("Email", validators=[InputRequired()])
password = PasswordField("Password", validators=[InputRequired()])
submit = SubmitField("Submit")
class LoginForm(BaseForm):
name = StringField("User Name or Email", validators=[InputRequired()])
password = PasswordField("Password", validators=[InputRequired()])
submit = SubmitField("Submit")
class ConfirmForm(BaseForm):
submit = SubmitField("Resend")
class ResetPasswordRequestForm(BaseForm):
email = EmailField("Email", validators=[InputRequired()])
submit = SubmitField("Submit")
class ResetPasswordForm(BaseForm):
password = PasswordField("Password", validators=[InputRequired()])
submit = SubmitField("Submit")

30
CTFd/forms/awards.py Normal file
View File

@@ -0,0 +1,30 @@
from wtforms import RadioField, StringField, TextAreaField
from wtforms.fields.html5 import IntegerField
from CTFd.forms import BaseForm
from CTFd.forms.fields import SubmitField
class AwardCreationForm(BaseForm):
name = StringField("Name")
value = IntegerField("Value")
category = StringField("Category")
description = TextAreaField("Description")
submit = SubmitField("Create")
icon = RadioField(
"Icon",
choices=[
("", "None"),
("shield", "Shield"),
("bug", "Bug"),
("crown", "Crown"),
("crosshairs", "Crosshairs"),
("ban", "Ban"),
("lightning", "Lightning"),
("skull", "Skull"),
("brain", "Brain"),
("code", "Code"),
("cowboy", "Cowboy"),
("angry", "Angry"),
],
)

30
CTFd/forms/challenges.py Normal file
View File

@@ -0,0 +1,30 @@
from wtforms import MultipleFileField, SelectField, StringField
from wtforms.validators import InputRequired
from CTFd.forms import BaseForm
from CTFd.forms.fields import SubmitField
class ChallengeSearchForm(BaseForm):
field = SelectField(
"Search Field",
choices=[
("name", "Name"),
("id", "ID"),
("category", "Category"),
("type", "Type"),
],
default="name",
validators=[InputRequired()],
)
q = StringField("Parameter", validators=[InputRequired()])
submit = SubmitField("Search")
class ChallengeFilesUploadForm(BaseForm):
file = MultipleFileField(
"Upload Files",
description="Attach multiple files using Control+Click or Cmd+Click.",
validators=[InputRequired()],
)
submit = SubmitField("Upload")

62
CTFd/forms/config.py Normal file
View File

@@ -0,0 +1,62 @@
from wtforms import BooleanField, SelectField, StringField
from wtforms.fields.html5 import IntegerField
from wtforms.widgets.html5 import NumberInput
from CTFd.forms import BaseForm
from CTFd.forms.fields import SubmitField
from CTFd.models import db
class ResetInstanceForm(BaseForm):
accounts = BooleanField(
"Accounts",
description="Deletes all user and team accounts and their associated information",
)
submissions = BooleanField(
"Submissions",
description="Deletes all records that accounts gained points or took an action",
)
challenges = BooleanField(
"Challenges", description="Deletes all challenges and associated data"
)
pages = BooleanField(
"Pages", description="Deletes all pages and their associated files"
)
notifications = BooleanField(
"Notifications", description="Deletes all notifications"
)
submit = SubmitField("Reset CTF")
class AccountSettingsForm(BaseForm):
domain_whitelist = StringField(
"Account Email Whitelist",
description="Comma-seperated email domains which users can register under (e.g. ctfd.io, gmail.com, yahoo.com)",
)
team_size = IntegerField(
widget=NumberInput(min=0), description="Amount of users per team"
)
verify_emails = SelectField(
"Verify Emails",
description="Control whether users must confirm their email addresses before playing",
choices=[("true", "Enabled"), ("false", "Disabled")],
default="false",
)
name_changes = SelectField(
"Name Changes",
description="Control whether users can change their names",
choices=[("true", "Enabled"), ("false", "Disabled")],
default="true",
)
submit = SubmitField("Update")
class ExportCSVForm(BaseForm):
table = SelectField(
"Database Table",
choices=list(
zip(sorted(db.metadata.tables.keys()), sorted(db.metadata.tables.keys()))
),
)
submit = SubmitField("Download CSV")

10
CTFd/forms/email.py Normal file
View File

@@ -0,0 +1,10 @@
from wtforms import TextAreaField
from wtforms.validators import InputRequired
from CTFd.forms import BaseForm
from CTFd.forms.fields import SubmitField
class SendEmailForm(BaseForm):
message = TextAreaField("Message", validators=[InputRequired()])
submit = SubmitField("Send")

17
CTFd/forms/fields.py Normal file
View File

@@ -0,0 +1,17 @@
from wtforms import SubmitField as _SubmitField
class SubmitField(_SubmitField):
"""
This custom SubmitField exists because wtforms is dumb.
See https://github.com/wtforms/wtforms/issues/205, https://github.com/wtforms/wtforms/issues/36
The .submit() handler in JS will break if the form has an input with the name or id of "submit" so submit fields need to be changed.
"""
def __init__(self, *args, **kwargs):
name = kwargs.pop("name", "_submit")
super().__init__(*args, **kwargs)
if self.name == "submit" or name:
self.id = name
self.name = name

View File

@@ -0,0 +1,26 @@
from wtforms import BooleanField, RadioField, StringField, TextAreaField
from wtforms.validators import InputRequired
from CTFd.forms import BaseForm
from CTFd.forms.fields import SubmitField
class NotificationForm(BaseForm):
title = StringField("Title", description="Notification title")
content = TextAreaField(
"Content",
description="Notification contents. Can consist of HTML and/or Markdown.",
)
type = RadioField(
"Notification Type",
choices=[("toast", "Toast"), ("alert", "Alert"), ("background", "Background")],
default="toast",
description="What type of notification users receive",
validators=[InputRequired()],
)
sound = BooleanField(
"Play Sound",
default=True,
description="Play sound for users when they receive the notification",
)
submit = SubmitField("Submit")

33
CTFd/forms/pages.py Normal file
View File

@@ -0,0 +1,33 @@
from wtforms import (
BooleanField,
HiddenField,
MultipleFileField,
StringField,
TextAreaField,
)
from wtforms.validators import InputRequired
from CTFd.forms import BaseForm
class PageEditForm(BaseForm):
title = StringField(
"Title", description="This is the title shown on the navigation bar"
)
route = StringField(
"Route",
description="This is the URL route that your page will be at (e.g. /page). You can also enter links to link to that page.",
)
draft = BooleanField("Draft")
hidden = BooleanField("Hidden")
auth_required = BooleanField("Authentication Required")
content = TextAreaField("Content")
class PageFilesUploadForm(BaseForm):
file = MultipleFileField(
"Upload Files",
description="Attach multiple files using Control+Click or Cmd+Click.",
validators=[InputRequired()],
)
type = HiddenField("Page Type", default="page", validators=[InputRequired()])

22
CTFd/forms/self.py Normal file
View File

@@ -0,0 +1,22 @@
from wtforms import PasswordField, SelectField, StringField
from wtforms.fields.html5 import DateField, URLField
from CTFd.forms import BaseForm
from CTFd.forms.fields import SubmitField
from CTFd.utils.countries import SELECT_COUNTRIES_LIST
class SettingsForm(BaseForm):
name = StringField("User Name")
email = StringField("Email")
password = PasswordField("Password")
confirm = PasswordField("Current Password")
affiliation = StringField("Affiliation")
website = URLField("Website")
country = SelectField("Country", choices=SELECT_COUNTRIES_LIST)
submit = SubmitField("Submit")
class TokensForm(BaseForm):
expiration = DateField("Expiration")
submit = SubmitField("Generate")

66
CTFd/forms/setup.py Normal file
View File

@@ -0,0 +1,66 @@
from wtforms import (
HiddenField,
PasswordField,
RadioField,
SelectField,
StringField,
TextAreaField,
)
from wtforms.fields.html5 import EmailField
from wtforms.validators import InputRequired
from CTFd.forms import BaseForm
from CTFd.forms.fields import SubmitField
from CTFd.utils.config import get_themes
class SetupForm(BaseForm):
ctf_name = StringField(
"Event Name", description="The name of your CTF event/workshop"
)
ctf_description = TextAreaField(
"Event Description", description="Description for the CTF"
)
user_mode = RadioField(
"User Mode",
choices=[("teams", "Team Mode"), ("users", "User Mode")],
default="teams",
description="Controls whether users join together in teams to play (Team Mode) or play as themselves (User Mode)",
validators=[InputRequired()],
)
name = StringField(
"Admin Username",
description="Your username for the administration account",
validators=[InputRequired()],
)
email = EmailField(
"Admin Email",
description="Your email address for the administration account",
validators=[InputRequired()],
)
password = PasswordField(
"Admin Password",
description="Your password for the administration account",
validators=[InputRequired()],
)
ctf_theme = SelectField(
"Theme",
description="CTFd Theme to use",
choices=list(zip(get_themes(), get_themes())),
default="core",
validators=[InputRequired()],
)
theme_color = HiddenField(
"Theme Color",
description="Color used by theme to control aesthetics. Requires theme support. Optional.",
)
start = StringField(
"Start Time", description="Time when your CTF is scheduled to start. Optional."
)
end = StringField(
"End Time", description="Time when your CTF is scheduled to end. Optional."
)
submit = SubmitField("Finish")

16
CTFd/forms/submissions.py Normal file
View File

@@ -0,0 +1,16 @@
from wtforms import SelectField, StringField
from wtforms.validators import InputRequired
from CTFd.forms import BaseForm
from CTFd.forms.fields import SubmitField
class SubmissionSearchForm(BaseForm):
field = SelectField(
"Search Field",
choices=[("provided", "Provided"), ("id", "ID")],
default="provided",
validators=[InputRequired()],
)
q = StringField("Parameter", validators=[InputRequired()])
submit = SubmitField("Search")

62
CTFd/forms/teams.py Normal file
View File

@@ -0,0 +1,62 @@
from wtforms import BooleanField, PasswordField, SelectField, StringField
from wtforms.fields.html5 import EmailField, URLField
from wtforms.validators import InputRequired
from CTFd.forms import BaseForm
from CTFd.forms.fields import SubmitField
from CTFd.utils.countries import SELECT_COUNTRIES_LIST
class TeamJoinForm(BaseForm):
name = StringField("Team Name", validators=[InputRequired()])
password = PasswordField("Team Password", validators=[InputRequired()])
submit = SubmitField("Join")
class TeamRegisterForm(BaseForm):
name = StringField("Team Name", validators=[InputRequired()])
password = PasswordField("Team Password", validators=[InputRequired()])
submit = SubmitField("Create")
class TeamSettingsForm(BaseForm):
name = StringField("Team Name")
confirm = PasswordField("Current Password")
password = PasswordField("Team Password")
affiliation = StringField("Affiliation")
website = URLField("Website")
country = SelectField("Country", choices=SELECT_COUNTRIES_LIST)
submit = SubmitField("Submit")
class TeamCaptainForm(BaseForm):
# Choices are populated dynamically at form creation time
captain_id = SelectField("Team Captain", choices=[], validators=[InputRequired()])
submit = SubmitField("Submit")
class TeamSearchForm(BaseForm):
field = SelectField(
"Search Field",
choices=[("name", "Name"), ("id", "ID"), ("affiliation", "Affiliation")],
default="name",
validators=[InputRequired()],
)
q = StringField("Parameter", validators=[InputRequired()])
submit = SubmitField("Search")
class TeamCreateForm(BaseForm):
name = StringField("Team Name", validators=[InputRequired()])
email = EmailField("Email")
password = PasswordField("Password")
website = URLField("Website")
affiliation = StringField("Affiliation")
country = SelectField("Country", choices=SELECT_COUNTRIES_LIST)
hidden = BooleanField("Hidden")
banned = BooleanField("Banned")
submit = SubmitField("Submit")
class TeamEditForm(TeamCreateForm):
pass

42
CTFd/forms/users.py Normal file
View File

@@ -0,0 +1,42 @@
from wtforms import BooleanField, PasswordField, SelectField, StringField
from wtforms.fields.html5 import EmailField
from wtforms.validators import InputRequired
from CTFd.forms import BaseForm
from CTFd.forms.fields import SubmitField
from CTFd.utils.countries import SELECT_COUNTRIES_LIST
class UserSearchForm(BaseForm):
field = SelectField(
"Search Field",
choices=[
("name", "Name"),
("id", "ID"),
("email", "Email"),
("affiliation", "Affiliation"),
("ip", "IP Address"),
],
default="name",
validators=[InputRequired()],
)
q = StringField("Parameter", validators=[InputRequired()])
submit = SubmitField("Search")
class UserEditForm(BaseForm):
name = StringField("User Name", validators=[InputRequired()])
email = EmailField("Email", validators=[InputRequired()])
password = PasswordField("Password")
website = StringField("Website")
affiliation = StringField("Affiliation")
country = SelectField("Country", choices=SELECT_COUNTRIES_LIST)
type = SelectField("Type", choices=[("user", "User"), ("admin", "Admin")])
verified = BooleanField("Verified")
hidden = BooleanField("Hidden")
banned = BooleanField("Banned")
submit = SubmitField("Submit")
class UserCreateForm(UserEditForm):
notify = BooleanField("Email account credentials to user", default=True)

View File

@@ -158,8 +158,9 @@ function submit_form() {
var target = "/api/v1/pages";
var method = "POST";
if (params.id) {
target += "/" + params.id;
let part = window.location.pathname.split("/").pop();
if (part !== "new") {
target += "/" + part;
method = "PATCH";
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -21,29 +21,29 @@
<div class="row">
<div class="col-md-12">
{% if q and field %}
<h5 class="text-muted text-center">Searching for challenges with <strong>{{ field }}</strong> matching <strong>{{ q }}</strong></h5>
<h6 class="text-muted text-center pb-3">{{ total }} results</h6>
<h5 class="text-muted text-center">
Searching for challenges with <strong>{{ field }}</strong> matching <strong>{{ q }}</strong>
</h5>
<h6 class="text-muted text-center pb-3">
{{ total }} results
</h6>
{% endif %}
{% with form = Forms.challenges.ChallengeSearchForm(field=field, q=q) %}
<form method="GET" class="form-inline">
<div class="form-group col-md-2">
<label for="sel1" class="sr-only" >Search Field</label>
<select class="form-control custom-select w-100" id="sel1" name="field">
<option value="name" {% if field == 'name' %}selected{% endif %}>Name</option>
<option value="id" {% if field == 'id' %}selected{% endif %}>ID</option>
<option value="category" {% if field == 'category' %}selected{% endif %}>Category</option>
<option value="type" {% if field == 'type' %}selected{% endif %}>Type</option>
</select>
{{ form.field(class="form-control custom-select w-100") }}
</div>
<div class="form-group col-md-8">
<label for="challenges-search" class="sr-only">Parameter</label>
<input type="text" class="form-control w-100" id="challenges-search" name="q" placeholder="Search for matching challenge" {% if q %}value="{{q}}"{% endif %}>
{{ form.q(class="form-control w-100", placeholder="Search for matching challenge") }}
</div>
<div class="form-group col-md-2">
<label class="sr-only">Search</label>
<button type="submit" class="btn btn-primary w-100"><i class="fas fa-search" aria-hidden="true"></i></button>
<button type="submit" class="btn btn-primary w-100">
<i class="fas fa-search" aria-hidden="true"></i>
</button>
</div>
</form>
{% endwith %}
</div>
</div>

View File

@@ -1,57 +1,43 @@
<div role="tabpanel" class="tab-pane config-section" id="accounts">
{% set verify_emails = "true" if verify_emails == True else "false" %}
{% set name_changes = "true" if name_changes == True else "false" %}
{% with form = Forms.config.AccountSettingsForm(verify_emails=verify_emails, name_changes=name_changes) %}
<form method="POST" autocomplete="off" class="w-100">
<div class="form-group">
<label>
Account Email Whitelist
{{ form.domain_whitelist.label }}
{{ form.domain_whitelist(class="form-control", value=domain_whitelist or "") }}
<small class="form-text text-muted">
Comma-seperated email domains which users can register under.
</small>
</label>
<input class="form-control" id='domain-whitelist' name='domain_whitelist' type='text'
placeholder=""
{% if domain_whitelist is defined and domain_whitelist != None %}value="{{ domain_whitelist }}"{% endif %}>
<small class="form-text text-muted">
e.g. ctfd.io,gmail.com,yahoo.com
{{ form.domain_whitelist.description }}
</small>
</div>
<div class="form-group">
<label>
Verify Emails<br>
{{ form.verify_emails.label }}
{{ form.verify_emails(class="form-control custom-select") }}
<small class="form-text text-muted">
Control whether users must confirm their email addresses before playing
{{ form.verify_emails.description }}
</small>
</label>
<select class="form-control custom-select" name="verify_emails">
<option value="true" {% if verify_emails == True %}selected{% endif %}>Enabled</option>
<option value="false" {% if verify_emails == False or verify_emails == None %}selected{% endif %}>Disabled</option>
</select>
</div>
<div class="form-group">
<label>
Team Size<br>
{{ form.team_size.label }}
{{ form.team_size(class="form-control", value=team_size) }}
<small class="form-text text-muted">
Amount of users per team
{{ form.team_size.description }}
</small>
</label>
<input class="form-control" id="team_size" name="team_size" type="number" min="0" {% if team_size %}value="{{ team_size }}"{% endif %}>
</div>
<div class="form-group">
<label>
Name Changes<br>
{{ form.name_changes.label }}
{{ form.name_changes(class="form-control custom-select") }}
<small class="form-text text-muted">
Control whether users can change their names
{{ form.name_changes.description }}
</small>
</label>
<select class="form-control custom-select" name="name_changes">
<option value="true" {% if name_changes == True or name_changes == None %}selected{% endif %}>Enabled</option>
<option value="false" {% if name_changes == False %}selected{% endif %}>Disabled</option>
</select>
</div>
<button type="submit" class="btn btn-md btn-primary float-right">Update</button>
{{ form.submit(class="btn btn-md btn-primary float-right") }}
</form>
{% endwith %}
</div>

View File

@@ -39,17 +39,15 @@
<input id="import-button" type="submit" class="btn btn-warning" value="Import">
</div>
<div role="tabpanel" class="tab-pane" id="save-csv">
{% with form = Forms.config.ExportCSVForm() %}
<form method="GET" action="{{ url_for('admin.export_csv') }}">
<div class="form-group">
<label for="container-files">Database Table</label>
<select class="form-control custom-select" name="table">
{% for table in database_tables %}
<option value="{{ table }}">{{ table }}</option>
{% endfor %}
</select>
{{ form.table.label }}
{{ form.table(class="form-control custom-select") }}
</div>
<input type="submit" class="btn btn-warning" value="Download CSV">
</form>
{% endwith %}
</div>
</div>
</div>

View File

@@ -69,18 +69,19 @@
</div>
</div>
</div>
{% with form = Forms.pages.PageFilesUploadForm() %}
<form id="media-library-upload" enctype="multipart/form-data">
<div class="form-group">
<label for="media-files">
Upload Files
</label>
<input type="file" name="file" id="media-files" class="form-control-file" multiple>
<b>{{ form.file.label }}</b>
{{ form.file(id="media-files", class="form-control-file") }}
<sub class="help-block">
Attach multiple files using Control+Click or Cmd+Click.
{{ form.file.description }}
</sub>
</div>
<input type="hidden" value="page" name="type">
</form>
{% endwith %}
</div>
<div class="modal-footer">
<div class="float-right">
@@ -106,29 +107,28 @@
{% endfor %}
</div>
{% set content = page.content if page is defined else "" %}
{% with form = Forms.pages.PageEditForm(content=content) %}
<form id="page-edit" method="POST">
<div class="form-group">
<div class="col-md-12">
<label>
Title<br>
<small class="text-muted">This is the title shown on the navigation bar</small>
</label>
<input class="form-control radius" id="route" type="text" name="title"
value="{% if page is defined %}{{ page.title }}{% endif %}" placeholder="Title">
{% set title = page.title if page is defined %}
<b>{{ form.title.label }}</b>
{{ form.title(class="form-control radius", id="route", placeholder="Title", value=title) }}
<small class="text-muted">
{{ form.title.description }}
</small>
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<label>
Route<br>
{% set route = page.route if page is defined %}
<b>{{ form.route.label }}</b>
{{ form.route(class="form-control radius", placeholder="Route", value=route) }}
<small class="text-muted">
This is the URL route that your page will be at (e.g. /page). You can
also enter links to link to that page.
{{ form.route.description }}
</small>
</label>
<input class="form-control radius" id="route" type="text" name="route"
value="{% if page is defined %}{{ page.route }}{% endif %}" placeholder="Route">
</div>
</div>
@@ -165,50 +165,28 @@
<span class="nav-link d-none d-md-block d-lg-block">|</span>
<div class="form-group pr-3">
Draft:
{% set draft = page is defined and page.draft == True %}
<select class="form-control custom-select" name="draft">
<option value="true" {% if draft == True %}selected{% endif %}>
True
</option>
<option value="false" {% if draft == False %}selected{% endif %}>
False
</option>
</select>
{{ form.draft(class="form-check-input", checked=draft) }}
{{ form.draft.label(class="form-check-label") }}
</div>
<div class="form-group pr-3">
Hidden:
{% set hidden = page is defined and page.hidden == True %}
<select class="form-control custom-select" name="hidden">
<option value="true" {% if hidden == True %}selected{% endif %}>True
</option>
<option value="false" {% if hidden == False %}selected{% endif %}>False
</option>
</select>
{{ form.hidden(class="form-check-input", checked=hidden) }}
{{ form.hidden.label(class="form-check-label") }}
</div>
<div class="form-group pr-3">
Authentication Required:
{% set auth_required = page is defined and page.auth_required == True %}
<select class="form-control custom-select" name="auth_required">
<option value="true" {% if auth_required == True %}selected{% endif %}>
True
</option>
<option value="false" {% if auth_required == False %}selected{% endif %}>
False
</option>
</select>
{{ form.auth_required(class="form-check-input", checked=auth_required) }}
{{ form.auth_required.label(class="form-check-label") }}
</div>
</div>
<br>
<div class="form-group">
<textarea id="admin-pages-editor" class="d-none"
name="content">{% if page is defined %}{{ page.content }}{% endif %}</textarea>
<input name='id' type='hidden'
{% if page is defined %}value="{{ page.id }}"{% endif %}>
{{ form.content(id="admin-pages-editor", class="d-none") }}
</div>
</div>
<div role="tabpanel" class="tab-pane content" id="content-preview" style="height:400px">
@@ -218,17 +196,14 @@
</div>
<div class="form-group float-right">
<input name='nonce' type='hidden' value="{{ nonce }}">
{{ form.nonce() }}
<button class="btn btn-primary" id="save-page">
{% if page is defined %}
Update
{% else %}
Save
{% endif %}
</button>
</div>
</form>
{% endwith %}
</div>
</div>
</div>

View File

@@ -1,22 +1,23 @@
{% with form = Forms.awards.AwardCreationForm() %}
<form id="user-award-form" method="POST">
<div class="form-group">
<label for="award-name-input">Name</label>
<input type="text" class="form-control" id="award-name-input" name="name">
<b>{{ form.name.label }}</b>
{{ form.name(class="form-control", id="award-name-input") }}
</div>
<div class="form-group">
<label for="award-value-input">Value</label>
<input type="number" class="form-control" id="award-value-input" name="value">
<b>{{ form.value.label }}</b>
{{ form.value(class="form-control", id="award-value-input") }}
</div>
<div class="form-group">
<label for="award-category-input">Category</label>
<input type="text" class="form-control" id="award-category-input" name="category">
<b>{{ form.category.label }}</b>
{{ form.category(class="form-control", id="award-category-input") }}
</div>
<div class="form-group">
<label for="award-description-input" class="control-label">Description</label>
<textarea id="award-description-input" class="form-control" name="description" rows="10"></textarea>
<b>{{ form.description.label }}</b>
{{ form.description(id="award-description-input", class="form-control", rows="5") }}
</div>
<div class="form-group">
<label for="award-icon-input">Icon</label>
<b>{{ form.icon.label }}</b>
<div class="pt-1">
<table class="table table-sm w-100">
<tr>
@@ -129,6 +130,7 @@
<div id="results">
</div>
<div class="modal-footer">
<button type="submit" id="award-create-button" class="btn btn-primary">Create</button>
{{ form.submit(id="award-create-button", class="btn btn-primary") }}
</div>
</form>
{% endwith %}

View File

@@ -21,13 +21,17 @@
</table>
<div class="col-md-12 mt-3">
{% with form = Forms.challenges.ChallengeFilesUploadForm() %}
<form id="file-add-form" method="POST">
<div class="form-group">
<input class="form-control-file" type="file" name="file" multiple="multiple">
<sub class="text-muted">Attach multiple files using Control+Click or Cmd+Click</sub>
{{ form.file(class="form-control-file") }}
<sub class="text-muted">
{{ form.file.description }}
</sub>
</div>
<div class="form-group">
<button class="btn btn-success float-right" id="submit-files">Upload</button>
{{ form.submit(class="btn btn-success float-right") }}
</div>
</form>
{% endwith %}
</div>

View File

@@ -1,16 +1,12 @@
{% with form = Forms.email.SendEmailForm() %}
<form id="user-mail-form" method="POST">
<div class="form-group">
<label>
Message
<br>
<small></small>
</label>
<textarea class="form-control" name="text" placeholder="" rows="15"></textarea>
{{ form.message.label }}
{{ form.message(class="form-control", rows="15") }}
</div>
<div id="results">
</div>
<button type="submit" class="btn btn-primary float-right">
Send
</button>
{{ form.submit(class="btn btn-primary float-right") }}
</form>
{% endwith %}

View File

@@ -1,57 +1,42 @@
{% with form = Forms.teams.TeamEditForm() %}
<form id="team-info-create-form" method="POST">
<input type="hidden" name="id">
<div class="form-group">
<label for="name">Team Name</label>
<input type="text" class="form-control" name="name" id="name"
{% if team is defined and team.name %}value="{{ team.name }}"{% endif %} required>
<b>{{ form.name.label }}</b>
{{ form.name(class="form-control") }}
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" name="email" id="email"
{% if team is defined and team.email %}value="{{ team.email }}"{% endif %}>
<b>{{ form.email.label }}</b>
{{ form.email(class="form-control") }}
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" id="password"/>
<b>{{ form.password.label }}</b>
{{ form.password(class="form-control") }}
</div>
<div class="form-group">
<label for="website">Website</label>
<input type="url" class="form-control" name="website" id="website"
{% if team is defined and team.website %}value="{{ team.website }}"{% endif %}>
<b>{{ form.website.label }}</b>
{{ form.website(class="form-control") }}
</div>
<div class="form-group">
<label for="affiliation">Affiliation</label>
<input type="text" class="form-control" name="affiliation" id="affiliation"
{% if team is defined and team.affiliation %}value="{{ team.affiliation }}"{% endif %}>
<b>{{ form.affiliation.label }}</b>
{{ form.affiliation(class="form-control") }}
</div>
<div class="form-group">
<label for="affiliation">Country</label>
<select class="form-control custom-select" id="country-input" name="country">
<option></option>
{% set countries = get_countries() %}
{% for country_code in countries.keys() %}
<option value="{{ country_code }}" {% if team is defined and team.country == country_code %}selected{% endif %}>
{{ countries[country_code] }}
</option>
{% endfor %}
</select>
<b>{{ form.country.label }}</b>
{{ form.country(class="form-control custom-select") }}
</div>
<div class="form-group">
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="hidden" id="hidden-checkbox"
{% if team is defined and team.hidden %}checked{% endif %}>
<label class="form-check-label" for="hidden-checkbox">Hidden</label>
{{ form.hidden(class="form-check-input") }}
{{ form.hidden.label(class="form-check-label") }}
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="banned" id="banned-checkbox"
{% if team is defined and team.banned %}checked{% endif %}>
<label class="form-check-label" for="banned-checkbox">Banned</label>
{{ form.banned(class="form-check-input") }}
{{ form.banned.label(class="form-check-label") }}
</div>
</div>
<div id="results">
</div>
<button id="update-team" type="submit" class="btn btn-primary btn-outlined float-right modal-action">
Submit
</button>
{{ form.submit(id="update-team", class="btn btn-primary btn-outlined float-right modal-action") }}
</form>
{% endwith %}

View File

@@ -1,57 +1,42 @@
{% with form = Forms.teams.TeamCreateForm(obj=team) %}
<form id="team-info-edit-form" method="POST">
<input type="hidden" name="id">
<div class="form-group">
<label for="name">Team Name</label>
<input type="text" class="form-control" name="name" id="name"
{% if team is defined and team.name %}value="{{ team.name }}"{% endif %} required>
{{ form.name.label }}
{{ form.name(class="form-control") }}
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" name="email" id="email"
{% if team is defined and team.email %}value="{{ team.email }}"{% endif %}>
{{ form.email.label }}
{{ form.email(class="form-control") }}
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" id="password"/>
{{ form.password.label }}
{{ form.password(class="form-control") }}
</div>
<div class="form-group">
<label for="website">Website</label>
<input type="url" class="form-control" name="website" id="website"
{% if team is defined and team.website %}value="{{ team.website }}"{% endif %}>
{{ form.website.label }}
{{ form.website(class="form-control") }}
</div>
<div class="form-group">
<label for="affiliation">Affiliation</label>
<input type="text" class="form-control" name="affiliation" id="affiliation"
{% if team is defined and team.affiliation %}value="{{ team.affiliation }}"{% endif %}>
{{ form.affiliation.label }}
{{ form.affiliation(class="form-control") }}
</div>
<div class="form-group">
<label for="affiliation">Country</label>
<select class="form-control custom-select" id="country-input" name="country">
<option></option>
{% set countries = get_countries() %}
{% for country_code in countries.keys() %}
<option value="{{ country_code }}" {% if team is defined and team.country == country_code %}selected{% endif %}>
{{ countries[country_code] }}
</option>
{% endfor %}
</select>
{{ form.country.label }}
{{ form.country(class="form-control custom-select") }}
</div>
<div class="form-group">
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="hidden" id="hidden-checkbox"
{% if team is defined and team.hidden %}checked{% endif %}>
<label class="form-check-label" for="hidden-checkbox">Hidden</label>
{{ form.hidden(class="form-check-input") }}
{{ form.hidden.label(class="form-check-label") }}
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="banned" id="banned-checkbox"
{% if team is defined and team.banned %}checked{% endif %}>
<label class="form-check-label" for="banned-checkbox">Banned</label>
{{ form.banned(class="form-check-input") }}
{{ form.banned.label(class="form-check-label") }}
</div>
</div>
<div id="results">
</div>
<button id="update-team" type="submit" class="btn btn-primary btn-outlined float-right modal-action">
Submit
</button>
{{ form.submit(id="update-team", class="btn btn-primary btn-outlined float-right modal-action") }}
</form>
{% endwith %}

View File

@@ -1,78 +1,59 @@
{% with form = Forms.users.UserCreateForm() %}
<form id="user-info-create-form" method="POST">
<input type="hidden" name="id">
<div class="form-group">
<label for="name">User Name</label>
<input type="text" class="form-control" name="name" id="name"
{% if user is defined and user.name %}value="{{ user.name }}"{% endif %} required>
{{ form.name.label }}
{{ form.name(class="form-control") }}
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" name="email" id="email"
{% if user is defined and user.email %}value="{{ user.email }}"{% endif %} required>
{{ form.email.label }}
{{ form.email(class="form-control") }}
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" id="password"/>
{{ form.password.label }}
{{ form.password(class="form-control") }}
</div>
<div class="form-group">
<label for="website">Website</label>
<input type="text" class="form-control" name="website" id="website"
{% if user is defined and user.website %}value="{{ user.website }}"{% endif %}>
{{ form.website.label }}
{{ form.website(class="form-control") }}
</div>
<div class="form-group">
<label for="affiliation">Affiliation</label>
<input type="text" class="form-control" name="affiliation" id="affiliation"
{% if user is defined and user.affiliation %}value="{{ user.affiliation }}"{% endif %}>
{{ form.affiliation.label }}
{{ form.affiliation(class="form-control") }}
</div>
<div class="form-group">
<label for="affiliation">Country</label>
<select class="form-control custom-select" id="country-input" name="country">
<option></option>
{% set countries = get_countries() %}
{% for country_code in countries.keys() %}
<option value="{{ country_code }}" {% if user is defined and user.country == country_code %}selected{% endif %}>
{{ countries[country_code] }}
</option>
{% endfor %}
</select>
{{ form.country.label }}
{{ form.country(class="form-control custom-select") }}
</div>
<div class="form-group">
<div class="form-check form-check-inline">
<select class="form-control form-inline custom-select" id="type-select" name="type">
<option value="user"{% if user is defined and user.type == 'user' %} selected{% endif %}>
User
</option>
<option value="admin"{% if user is defined and user.type == 'admin' %} selected{% endif %}>
Admin
</option>
</select>
{{ form.type(class="form-control form-inline custom-select", id="type-select") }}
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="verified" id="verified-checkbox">
<label class="form-check-label" for="verified-checkbox">Verified</label>
{{ form.verified(class="form-check-input") }}
{{ form.verified.label(class="form-check-label") }}
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="hidden" id="hidden-checkbox">
<label class="form-check-label" for="hidden-checkbox">Hidden</label>
{{ form.hidden(class="form-check-input") }}
{{ form.hidden.label(class="form-check-label") }}
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="banned" id="banned-checkbox">
<label class="form-check-label" for="banned-checkbox">Banned</label>
{{ form.banned(class="form-check-input") }}
{{ form.banned.label(class="form-check-label") }}
</div>
</div>
{% if can_send_mail() %}
<div class="form-group">
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="notify" id="notify-checkbox" checked>
<label class="form-check-label" for="notify-checkbox">Email account credentials to user</label>
{{ form.notify(class="form-check-input", id="notify-checkbox") }}
{{ form.notify.label(class="form-check-label") }}
</div>
</div>
{% endif %}
<div id="results">
</div>
<button id="update-user" type="submit" class="btn btn-primary btn-outlined float-right modal-action">
Submit
</button>
{{ form.submit(id="update-user", class="btn btn-primary btn-outlined float-right modal-action") }}
</form>
{% endwith %}

View File

@@ -1,68 +1,48 @@
{% with form = Forms.users.UserEditForm(obj=user) %}
<form id="user-info-edit-form">
<input type="hidden" name="id">
<div class="form-group">
<label for="name">User Name</label>
<input type="text" class="form-control" name="name" id="name"
{% if user is defined and user.name %}value="{{ user.name }}"{% endif %} required>
{{ form.name.label }}
{{ form.name(class="form-control") }}
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" name="email" id="email"
{% if user is defined and user.email %}value="{{ user.email }}"{% endif %} required>
{{ form.email.label }}
{{ form.email(class="form-control") }}
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" id="password"/>
{{ form.password.label }}
{{ form.password(class="form-control") }}
</div>
<div class="form-group">
<label for="website">Website</label>
<input type="text" class="form-control" name="website" id="website"
{% if user is defined and user.website %}value="{{ user.website }}"{% endif %}>
{{ form.website.label }}
{{ form.website(class="form-control") }}
</div>
<div class="form-group">
<label for="affiliation">Affiliation</label>
<input type="text" class="form-control" name="affiliation" id="affiliation"
{% if user is defined and user.affiliation %}value="{{ user.affiliation }}"{% endif %}>
{{ form.affiliation.label }}
{{ form.affiliation(class="form-control") }}
</div>
<div class="form-group">
<label for="affiliation">Country</label>
<select class="form-control custom-select" id="country-input" name="country">
<option></option>
{% set countries = get_countries() %}
{% for country_code in countries.keys() %}
<option value="{{ country_code }}" {% if user is defined and user.country == country_code %}selected{% endif %}>
{{ countries[country_code] }}
</option>
{% endfor %}
</select>
{{ form.country.label }}
{{ form.country(class="form-control custom-select") }}
</div>
<div class="form-group">
<div class="form-check form-check-inline">
<select class="form-control form-inline custom-select" id="type-select" name="type">
<option value="user"{% if user is defined and user.type == 'user' %} selected{% endif %}>
User
</option>
<option value="admin"{% if user is defined and user.type == 'admin' %} selected{% endif %}>
Admin
</option>
</select>
{{ form.type(class="form-control form-inline custom-select", id="type-select") }}
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="verified" id="verified-checkbox" {% if user is defined and user.verified %}checked{% endif %}>
<label class="form-check-label" for="verified-checkbox">Verified</label>
{{ form.verified(class="form-check-input") }}
{{ form.verified.label(class="form-check-label") }}
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="hidden" id="hidden-checkbox" {% if user is defined and user.hidden %}checked{% endif %}>
<label class="form-check-label" for="hidden-checkbox">Hidden</label>
{{ form.hidden(class="form-check-input") }}
{{ form.hidden.label(class="form-check-label") }}
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" name="banned" id="banned-checkbox" {% if user is defined and user.banned %}checked{% endif %}>
<label class="form-check-label" for="banned-checkbox">Banned</label>
{{ form.banned(class="form-check-input") }}
{{ form.banned.label(class="form-check-label") }}
</div>
</div>
<div id="results">
</div>
<button id="update-user" type="submit" class="btn btn-primary btn-outlined float-right modal-action">
Submit
</button>
{{ form.submit(class="btn btn-primary btn-outlined float-right modal-action") }}
</form>
{% endwith %}

View File

@@ -9,67 +9,55 @@
<div class="container">
<div class="row">
<div class="col-md-12">
{% with form = Forms.notifications.NotificationForm() %}
<form method="POST" id="notifications_form">
<div class="form-group">
<label>
Title
<b>{{ form.title.label }}</b>
{{ form.title(class="form-control") }}
<small class="form-text text-muted">
Notification title
{{ form.title.description }}
</small>
</label>
<input class="form-control" type="text" name="title">
</div>
<div class="form-group">
<label>
Content
<b>{{ form.content.label }}</b>
{{ form.content(class="form-control", rows="3") }}
<small class="form-text text-muted">
Notification contents can be made up of HTML
{{ form.content.description }}
</small>
</label>
<textarea class="form-control" type="text" name="content" rows="3"></textarea>
</div>
<div class="form-row">
<div class="col">
<div class="form-group">
<label>
Type
<b>{{ form.type.label }}</b>
</div>
{% for radio in form.type %}
<div class="form-check form-check-inline pr-1">
{{ radio(class="form-check-input") }}
{{ radio.label(class="form-check-label") }}
</div>
{% endfor %}
<small class="form-text text-muted">
What type of notification users receive
{{ form.type.description }}
</small>
</label>
</div>
<div class="form-check form-check-inline pr-1">
<input class="form-check-input" type="radio" name="type" value="toast" id="type-radio-toast" checked>
<label class="form-check-label" for="type-radio-toast">Toast</label>
</div>
<div class="form-check form-check-inline pr-1">
<input class="form-check-input" type="radio" name="type" value="alert" id="type-radio-alert">
<label class="form-check-label" for="type-radio-alert">Alert</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="type" value="background" id="type-radio-bg">
<label class="form-check-label" for="type-radio-bg">Background</label>
</div>
</div>
<div class="col">
<div class="form-group">
<label>
Sound
<small class="form-text text-muted">
Play sound for users
</small>
</label>
<b>{{ form.sound.label }}</b>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="sound" value="true" id="sound-enable" checked>
<label class="form-check-label" for="sound-enable">Play Sound</label>
{{ form.sound(class="form-check-input") }}
{{ form.sound.label(class="form-check-label") }}
</div>
<small class="form-text text-muted">
{{ form.sound.description }}
</small>
</div>
</div>
<div class="float-right">
<button type="submit" class="btn btn-success text-center">Submit</button>
{{ form.submit(class="btn btn-success text-center") }}
</div>
</form>
{% endwith %}
</div>
</div>
</div>

View File

@@ -12,6 +12,7 @@
<div class="container">
<div class="row">
<div class="col-md-6 offset-md-3">
{% with form = Forms.config.ResetInstanceForm() %}
<form method="POST" id="reset-ctf-form">
<div class="alert alert-danger" role="alert">
<p>
@@ -38,9 +39,8 @@
<div class="form-group pb-2">
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="accounts"> Accounts
</label>
{{ form.accounts(class="form-check-input") }}
{{ form.accounts.label(class="form-check-label") }}
</div>
<span class="text-muted">
Deletes all user and team accounts and their associated information<br>
@@ -50,9 +50,8 @@
<div class="form-group pb-2">
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="submissions"> Submissions
</label>
{{ form.submissions(class="form-check-input") }}
{{ form.submissions.label(class="form-check-label") }}
</div>
<span class="text-muted">
Deletes all records that accounts gained points or took an action<br>
@@ -62,9 +61,8 @@
<div class="form-group pb-2">
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="challenges"> Challenges
</label>
{{ form.challenges(class="form-check-input") }}
{{ form.challenges.label(class="form-check-label") }}
</div>
<span class="text-muted">
Deletes all challenges and associated data<br>
@@ -74,9 +72,8 @@
<div class="form-group pb-2">
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="pages"> Pages
</label>
{{ form.pages(class="form-check-input") }}
{{ form.pages.label(class="form-check-label") }}
</div>
<span class="text-muted">
Deletes all pages and their associated files<br>
@@ -86,9 +83,8 @@
<div class="form-group pb-2">
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" type="checkbox" name="notifications"> Notifications
</label>
{{ form.notifications(class="form-check-input") }}
{{ form.notifications.label(class="form-check-label") }}
</div>
<span class="text-muted">
Deletes all notifications<br>
@@ -98,12 +94,11 @@
<br>
<input id="nonce" type="hidden" name="nonce" value="{{ nonce }}">
{{ form.nonce() }}
<button class="btn btn-warning btn-lg btn-block">
Reset CTF
</button>
{{ form.submit(class="btn btn-warning btn-lg btn-block") }}
</form>
{% endwith %}
</div>
</div>
</div>

View File

@@ -16,27 +16,29 @@
<div class="row">
<div class="col-md-12">
{% if q and field %}
<h5 class="text-muted text-center">Searching for submissions with <strong>{{ field }}</strong> matching <strong>{{ q }}</strong></h5>
<h6 class="text-muted text-center pb-3">Page {{ submissions.page }} of {{ submissions.total }} results</h6>
<h5 class="text-muted text-center">
Searching for submissions with <strong>{{ field }}</strong> matching <strong>{{ q }}</strong>
</h5>
<h6 class="text-muted text-center pb-3">
Page {{ submissions.page }} of {{ submissions.total }} results
</h6>
{% endif %}
{% with form = Forms.submissions.SubmissionSearchForm(field=field, q=q) %}
<form method="GET" class="form-inline">
<div class="form-group col-md-2">
<label for="sel1" class="sr-only" >Search Field</label>
<select class="form-control custom-select w-100" id="sel1" name="field">
<option value="provided" {% if field == 'provided' %}selected{% endif %}>Provided</option>
<option value="id" {% if field == 'id' %}selected{% endif %}>ID</option>
</select>
{{ form.field(class="form-control custom-select w-100") }}
</div>
<div class="form-group col-md-8">
<label for="team-name-search" class="sr-only">Parameter</label>
<input type="text" class="form-control w-100" id="team-name-search" name="q" placeholder="Search for matching submission" {% if q %}value="{{q}}"{% endif %}>
{{ form.q(class="form-control w-100", placeholder="Search for matching submission") }}
</div>
<div class="form-group col-md-2">
<label for="team-name-search" class="sr-only">Search</label>
<button type="submit" class="btn btn-primary w-100"><i class="fas fa-search" aria-hidden="true"></i></button>
<button type="submit" class="btn btn-primary w-100">
<i class="fas fa-search" aria-hidden="true"></i>
</button>
</div>
</form>
{% endwith %}
</div>
</div>

View File

@@ -20,28 +20,29 @@
<div class="row">
<div class="col-md-12">
{% if q and field %}
<h5 class="text-muted text-center">Searching for teams with <strong>{{ field }}</strong> matching <strong>{{ q }}</strong></h5>
<h6 class="text-muted text-center pb-3">Page {{ teams.page }} of {{ teams.total }} results</h6>
<h5 class="text-muted text-center">
Searching for teams with <strong>{{ field }}</strong> matching <strong>{{ q }}</strong>
</h5>
<h6 class="text-muted text-center pb-3">
Page {{ teams.page }} of {{ teams.total }} results
</h6>
{% endif %}
{% with form = Forms.teams.TeamSearchForm() %}
<form method="GET" class="form-inline">
<div class="form-group col-md-2">
<label for="sel1" class="sr-only" >Search Field</label>
<select class="form-control custom-select w-100" id="sel1" name="field">
<option value="name" {% if field == 'name' %}selected{% endif %}>Name</option>
<option value="id" {% if field == 'id' %}selected{% endif %}>ID</option>
<option value="affiliation" {% if field == 'affiliation' %}selected{% endif %}>Affiliation</option>
</select>
{{ form.field(class="form-control custom-select w-100") }}
</div>
<div class="form-group col-md-8">
<label for="team-search" class="sr-only">Parameter</label>
<input type="text" class="form-control w-100" id="team-search" name="q" placeholder="Search for matching teams" {% if q %}value="{{q}}"{% endif %}>
{{ form.q(class="form-control w-100", placeholder="Search for matching teams") }}
</div>
<div class="form-group col-md-2">
<label class="sr-only">Search</label>
<button type="submit" class="btn btn-primary w-100"><i class="fas fa-search" aria-hidden="true"></i></button>
<button type="submit" class="btn btn-primary w-100">
<i class="fas fa-search" aria-hidden="true"></i>
</button>
</div>
</form>
{% endwith %}
</div>
</div>

View File

@@ -21,30 +21,29 @@
<div class="row">
<div class="col-md-12">
{% if q and field %}
<h5 class="text-muted text-center">Searching for users with <strong>{{ field }}</strong> matching <strong>{{ q }}</strong></h5>
<h6 class="text-muted text-center pb-3">Page {{ users.page }} of {{ users.total }} results</h6>
<h5 class="text-muted text-center">
Searching for users with <strong>{{ field }}</strong> matching <strong>{{ q }}</strong>
</h5>
<h6 class="text-muted text-center pb-3">
Page {{ users.page }} of {{ users.total }} results
</h6>
{% endif %}
{% with form = Forms.users.UserSearchForm(field=field, q=q) %}
<form method="GET" class="form-inline">
<div class="form-group col-md-2">
<label for="sel1" class="sr-only" >Search Field</label>
<select class="form-control custom-select w-100" id="sel1" name="field">
<option value="name" {% if field == 'name' %}selected{% endif %}>Name</option>
<option value="id" {% if field == 'id' %}selected{% endif %}>ID</option>
<option value="email" {% if field == 'email' %}selected{% endif %}>Email</option>
<option value="affiliation" {% if field == 'affiliation' %}selected{% endif %}>Affiliation</option>
<option value="ip" {% if field == 'ip' %}selected{% endif %}>IP Address</option>
</select>
{{ form.field(class="form-control custom-select w-100") }}
</div>
<div class="form-group col-md-8">
<label for="users-search" class="sr-only">Parameter</label>
<input type="text" class="form-control w-100" id="users-search" name="q" placeholder="Search for matching user" {% if q %}value="{{q}}"{% endif %}>
{{ form.q(class="form-control w-100", placeholder="Search for matching users") }}
</div>
<div class="form-group col-md-2">
<label for="users-search" class="sr-only">Search</label>
<button type="submit" class="btn btn-primary w-100"><i class="fas fa-search" aria-hidden="true"></i></button>
<button type="submit" class="btn btn-primary w-100">
<i class="fas fa-search" aria-hidden="true"></i>
</button>
</div>
</form>
{% endwith %}
</div>
</div>

View File

@@ -15,7 +15,7 @@
<script type="text/javascript">
var init = {
'urlRoot': "{{ request.script_root }}",
'csrfNonce': "{{ nonce }}",
'csrfNonce': "{{ Session.nonce }}",
'userMode': "{{ Configs.user_mode }}",
'userId': {{ Session.id }},
'start': {{ Configs.start | tojson }},

View File

@@ -26,15 +26,17 @@
<hr>
{% with form = Forms.auth.ConfirmForm() %}
<form method="POST" action="{{ url_for('auth.confirm') }}">
<h4 class="text-center">
Need to resend the confirmation email?
</h4>
<div class="col-md-12 text-center">
<button type="submit" tabindex="0" class="btn btn-md btn-primary btn-outlined">Resend</button>
{{ form.submit(class="btn btn-md btn-primary btn-outlined") }}
</div>
<input type="hidden" name="nonce" value="{{ nonce }}">
{{ form.nonce() }}
</form>
{% endwith %}
</div>
</div>
</div>

View File

@@ -22,18 +22,15 @@
<hr>
{% endif %}
{% with form = Forms.auth.LoginForm() %}
<form method="post" accept-charset="utf-8" autocomplete="off">
<div class="form-group">
<label>
User Name or Email
</label>
<input class="form-control" type="text" name="name" />
<b>{{ form.name.label }}</b>
{{ form.name(class="form-control", value=name) }}
</div>
<div class="form-group">
<label>
Password
</label>
<input class="form-control" type="password" name="password" />
<b>{{ form.password.label }}</b>
{{ form.password(class="form-control", value=password) }}
</div>
<div class="row pt-3">
<div class="col-md-6">
@@ -42,13 +39,12 @@
</a>
</div>
<div class="col-md-6">
<button type="submit" class="btn btn-md btn-primary btn-outlined float-right">
Submit
</button>
{{ form.submit(class="btn btn-md btn-primary btn-outlined float-right") }}
</div>
</div>
<input type="hidden" name="nonce" value="{{ nonce }}">
{{ form.nonce() }}
</form>
{% endwith %}
</div>
</div>
</div>

View File

@@ -22,32 +22,28 @@
<hr>
{% endif %}
{% with form = Forms.auth.RegistrationForm() %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form">
<div class="form-group">
<label>
User Name
</label>
<input class="form-control" type="text" name="name" {% if name %}value="{{ name }}"{% endif %} />
{{ form.name.label }}
{{ form.name(class="form-control", value=name) }}
</div>
<div class="form-group">
<label>
Email
</label>
<input class="form-control" type="text" name="email" {% if email %}value="{{ email }}"{% endif %} />
{{ form.email.label }}
{{ form.email(class="form-control", value=email) }}
</div>
<div class="form-group">
<label>
Password
</label>
<input class="form-control" type="password" name="password" {% if password %}value="{{ password }}"{% endif %}/>
{{ form.password.label }}
{{ form.password(class="form-control", value=password) }}
</div>
<div class="row pt-3">
<div class="col-md-12">
<button type="submit" class="btn btn-md btn-primary btn-outlined float-right">Submit</button>
{{ form.submit(class="btn btn-md btn-primary btn-outlined float-right") }}
</div>
</div>
<input type="hidden" name="nonce" value="{{ nonce }}">
{{ form.nonce() }}
</form>
{% endwith %}
</div>
</div>
</div>

View File

@@ -14,34 +14,46 @@
<div class="col-md-6 offset-md-3">
{% include "components/errors.html" %}
{% if can_send_mail() %}
{% if mode == "set" %}
{% with form = Forms.auth.ResetPasswordForm() %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<input name='nonce' type='hidden' value="{{ nonce }}">
{% if mode %}
<div class="form-group">
<label for="password-input">
Password
</label>
<input class="form-control" type="password" name="password" id="password-input" />
<div class="row">
<div class="col-md-12">
<p>You can now reset the password for your account and log in. Please enter in a new password below.</p>
</div>
{% else %}
<div class="form-group">
<label for="email-input">
Email
</label>
<input class="form-control" type="text" name="email" id="email-input" />
</div>
{% endif %}
<div class="form-group">
{{ form.password.label }}
{{ form.password(class="form-control") }}
</div>
<div class="row">
<div class="col-md-6 offset-md-6">
<button type="submit" tabindex="0" class="btn btn-md btn-primary float-right">Submit</button>
{{ form.submit(class="btn btn-md btn-primary float-right") }}
</div>
</div>
{{ form.nonce() }}
</form>
{% endwith %}
{% else %}
<h3 class="text-center">Contact a CTF organizer</h3>
<p>This CTF is not configured to send email.</p>
<p>Please contact an organizer to have your password reset</p>
{% with form = Forms.auth.ResetPasswordRequestForm() %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal">
<div class="row">
<div class="col-md-12">
<p>Please provide the email address associated with your account below.</p>
</div>
</div>
<div class="form-group">
{{ form.email.label }}
{{ form.email(class="form-control") }}
</div>
<div class="row">
<div class="col-md-6 offset-md-6">
{{ form.submit(class="btn btn-md btn-primary float-right") }}
</div>
</div>
{{ form.nonce() }}
</form>
{% endwith %}
{% endif %}
</div>
</div>

View File

@@ -22,91 +22,70 @@
<div class="tab-pane fade show active" id="profile" role="tabpanel">
{% include "components/errors.html" %}
{% with form = Forms.self.SettingsForm(country=country) %}
<form id="user-profile-form" method="post" accept-charset="utf-8" autocomplete="off" role="form"
class="form-horizontal">
<div class="form-group">
<label for="name-input">
User Name
</label>
<input class="form-control" type="text" name="name" id="name-input" value="{{name}}" />
{{ form.name.label }}
{{ form.name(class="form-control", value=name) }}
</div>
<div class="form-group">
<label for="email-input">
Email
</label>
<input class="form-control" type="email" name="email" id="email-input" value="{{email}}" />
{{ form.email.label }}
{{ form.email(class="form-control", value=email) }}
</div>
<hr>
<div class="form-group">
<label for="confirm-input">
Current Password
</label>
<input class="form-control" type="password" name="confirm" id="confirm-input" />
{{ form.confirm.label }}
{{ form.confirm(class="form-control") }}
</div>
<div class="form-group">
<label for="password-input">
New Password
</label>
<input class="form-control" type="password" name="password" id="password-input" />
{{ form.password.label }}
{{ form.password(class="form-control") }}
</div>
<hr>
<div class="form-group">
<label for="affiliation-input">
Affiliation
</label>
<input class="form-control" type="text" name="affiliation" id="affiliation-input"
value="{% if affiliation %}{{affiliation}}{% endif %}" />
{{ form.affiliation.label }}
{{ form.affiliation(class="form-control", value=affiliation or "") }}
</div>
<div class="form-group">
<label for="website-input">
Website
</label>
<input class="form-control" type="url" name="website" id="website-input"
value="{% if website %}{{website}}{% endif %}" />
{{ form.website.label }}
{{ form.website(class="form-control", value=website or "") }}
</div>
<div class="form-group">
<label for="country-input">
Country
</label>
<select class="form-control custom-select" id="country-input" name="country">
<option value=""></option>
{% set countries = get_countries() %}
{% for country_code in countries.keys() %}
<option value="{{ country_code }}" {% if country == country_code %}selected{% endif %}>
{{ countries[country_code] }}</option>
{% endfor %}
</select>
{{ form.country.label }}
{{ form.country(class="form-control custom-select", value=country) }}
</div>
<div id="results" class="form-group">
</div>
<div class="form-group">
<button type="submit" tabindex="0" class="btn btn-md btn-primary btn-outlined float-right">Submit</button>
{{ form.submit(class="btn btn-md btn-primary btn-outlined float-right") }}
</div>
</form>
{% endwith %}
</div>
<div class="tab-pane fade" id="tokens" role="tabpanel">
{% with form = Forms.self.TokensForm() %}
<form method="POST" id="user-token-form">
<div class="form-group">
<label for="name-input">
Expiration
</label>
<input class="form-control" type="date" name="expiration" id="expiration-input" />
{{ form.expiration.label }}
{{ form.expiration(class="form-control") }}
</div>
<div class="form-group text-right">
<button type="submit" class="btn btn-md btn-primary btn-outlined">Generate</button>
{{ form.submit(class="btn btn-md btn-primary btn-outlined") }}
</div>
</form>
{% endwith %}
{% if tokens %}
<hr>
<h4>Active Tokens</h4>
<h4 class="text-center">Active Tokens</h4>
<table class="table table-striped">
<thead>
<tr>

View File

@@ -13,6 +13,7 @@
<div class="col-md-8 offset-md-2">
{% include "components/errors.html" %}
{% with form = Forms.setup.SetupForm() %}
<form method="post" accept-charset="utf-8" autocomplete="off" role="form" class="form-horizontal" id="setup-form">
<ul class="nav nav-pills nav-fill mb-4">
<li class="nav-item">
@@ -35,38 +36,32 @@
<div class="tab-content">
<div class="tab-pane fade show active" id="general" role="tabpanel">
<div class="form-group">
<label>
CTF Name<br>
<b>{{ form.ctf_name.label }}</b>
{{ form.ctf_name(class="form-control") }}
<small class="form-text text-muted">
Name for the CTF
{{ form.ctf_name.description }}
</small>
</label>
<input class="form-control" type="text" id="ctf_name" name="ctf_name" />
</div>
<div class="form-group">
<label>
CTF Description<br>
<b>{{ form.ctf_description.label }}</b>
{{ form.ctf_description(class="form-control", rows="5") }}
<small class="form-text text-muted">
Description for the CTF
{{ form.ctf_description.description }}
</small>
</label>
<textarea class="form-control" type="text" id="ctf_description" name="ctf_description" rows="5"></textarea>
</div>
<div class="form-group">
<label>
CTF User Mode
<b>{{ form.user_mode.label }}</b>
{% for radio in form.user_mode %}
<div class="form-check ml-3">
{{ radio(class="form-check-input") }}
{{ radio.label }}
</div>
{% endfor %}
<small class="form-text text-muted">
User Mode for the CTF. <br>
Dictates whether users join teams to play (Team Mode) or
play as themselves (User Mode)
{{ form.user_mode.description }}
</small>
</label>
<select class="form-control custom-select" id="user_mode" name="user_mode">
<option value="teams">Team Mode</option>
<option value="users">User Mode</option>
</select>
</div>
<div class="float-right">
@@ -77,31 +72,25 @@
</div>
<div class="tab-pane fade" id="administration" role="tabpanel">
<div class="form-group">
<label>
Admin Username<br>
<b>{{ form.name.label }}</b>
{{ form.name(class="form-control") }}
<small class="form-text text-muted">
Your username for the administration account
{{ form.name.description }}
</small>
</label>
<input class="form-control" type="text" name="name" required/>
</div>
<div class="form-group">
<label>
Admin Email<br>
<b>{{ form.email.label }}</b>
{{ form.email(class="form-control") }}
<small class="form-text text-muted">
Your email address for the administration account
{{ form.email.description }}
</small>
</label>
<input class="form-control" type="email" name="email" required/>
</div>
<div class="form-group">
<label>
Admin Password<br>
<b>{{ form.password.label }}</b>
{{ form.password(class="form-control") }}
<small class="form-text text-muted">
Your password for the administration account
{{ form.password.description }}
</small>
</label>
<input class="form-control" type="password" name="password" required/>
</div>
<div class="form-check">
@@ -119,28 +108,17 @@
</div>
<div class="tab-pane fade" id="style" role="tabpanel">
<div class="form-group">
<label>
Theme<br>
<b>{{ form.ctf_theme.label }}</b>
{{ form.ctf_theme(class="form-control custom-select") }}
<small class="form-text text-muted">
CTFd Theme to use
{{ form.ctf_theme.description }}
</small>
</label>
<select class="form-control custom-select" name="ctf_theme">
{% for theme in themes %}
<option>{{ theme }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label>
Theme Color
<small class="form-text text-muted">
Color used by theme to control aesthetics. Requires theme support.
</small>
</label>
<b>{{ form.theme_color.label }}</b>
<br>
<div class="d-inline-block">
<input type="hidden" name="theme_color" id="config-color-input">
{{ form.theme_color(id="config-color-input") }}
<div class="btn-group">
<input type="color" id="config-color-picker" class="pr-1" style="width: 100px; height: 30px;" value="">
</div>
@@ -148,6 +126,9 @@
<button type="button" id="config-color-reset">Reset</button>
</div>
</div>
<small class="form-text text-muted">
{{ form.theme_color.description }}
</small>
</div>
<div class="float-right">
<button type="button" class="btn btn-primary btn-outlined tab-next" data-href="#datetime">
@@ -157,12 +138,7 @@
</div>
<div class="tab-pane fade" id="datetime" role="tabpanel">
<div class="form-group">
<label>
Start Time<br>
<small class="form-text text-muted">
Time when your CTF is scheduled to start. Optional.
</small>
</label>
<b>{{ form.start.label }}</b>
<div class="row">
<div class="col-md-4">
<label>Date</label>
@@ -174,18 +150,16 @@
</div>
<div class="col-md-4">
<label>UTC Preview</label>
<input class="form-control" type="text" id="start-preview" name="start" readonly/>
{{ form.start(class="form-control", id="start-preview", readonly=True) }}
</div>
</div>
<small class="form-text text-muted">
{{ form.start.description }}
</small>
</div>
<div class="form-group">
<label>
End Time<br>
<small class="form-text text-muted">
Time when your CTF is scheduled to end. Optional.
</small>
</label>
<b>{{ form.end.label }}</b>
<div class="row">
<div class="col-md-4">
<label>Date</label>
@@ -197,9 +171,12 @@
</div>
<div class="col-md-4">
<label>UTC Preview</label>
<input class="form-control" type="text" id="end-preview" name="end" readonly />
{{ form.start(class="form-control", id="end-preview", readonly=True) }}
</div>
</div>
<small class="form-text text-muted">
{{ form.end.description }}
</small>
</div>
<div class="float-right">
@@ -231,16 +208,14 @@
<br>
<div class="submit-row float-right">
<button type="submit" tabindex="0" class="btn btn-md btn-primary btn-outlined">
Finish
</button>
{{ form.submit(class="btn btn-md btn-primary btn-outlined") }}
</div>
</div>
</div>
<input type="hidden" name="nonce" value="{{ nonce }}">
{# This nonce is implemented specially in the route itself #}
{{ form.nonce() }}
</form>
{% endwith %}
</div>
</div>

View File

@@ -14,24 +14,24 @@
<div class="col-md-6 offset-md-3">
{% include "components/errors.html" %}
{% with form = Forms.teams.TeamJoinForm() %}
<form method="POST">
<div class="form-group">
<label>Team Name:</label>
<input class="form-control" type="text" name="name">
{{ form.name.label }}
{{ form.name(class="form-control") }}
</div>
<div class="form-group">
<label>Team Password:</label>
<input class="form-control" type="password" name="password">
{{ form.password.label }}
{{ form.password(class="form-control") }}
</div>
<input type="hidden" name="nonce" value="{{ nonce }}">
<div class="row pt-3">
<div class="col-md-12">
<button type="submit" class="btn btn-success float-right">
Join
</button>
{{ form.submit(class="btn btn-success float-right") }}
</div>
</div>
{{ form.nonce() }}
</form>
{% endwith %}
</div>
</div>
</div>

View File

@@ -14,25 +14,25 @@
<div class="col-md-6 offset-md-3">
{% include "components/errors.html" %}
{% with form = Forms.teams.TeamRegisterForm() %}
<form method="POST">
<div class="form-group">
<label>Team Name:</label>
<input class="form-control" type="text" name="name">
{{ form.name.label }}
{{ form.name(class="form-control") }}
</div>
<div class="form-group">
<label>Team Password:</label>
<input class="form-control" type="password" name="password">
{{ form.password.label }}
{{ form.password(class="form-control") }}
</div>
<input type="hidden" name="nonce" value="{{ nonce }}">
<div class="row pt-3">
<div class="col-md-12">
<p>After creating your team, share the team name and password with your teammates so they can join your team.</p>
<button type="submit" class="btn btn-success float-right">
Create
</button>
{{ form.submit(class="btn btn-success float-right") }}
</div>
</div>
{{ form.nonce() }}
</form>
{% endwith %}
</div>
</div>
</div>

View File

@@ -14,50 +14,38 @@
</button>
</div>
<div class="modal-body clearfix">
{% with form = Forms.teams.TeamSettingsForm(obj=team) %}
<form id="team-info-form" method="POST">
<div class="form-group">
<label for="name">Team Name</label>
<input type="text" class="form-control" name="name" id="name"
{% if team is defined and team.name %}value="{{ team.name }}"{% endif %} required />
{{ form.name.label }}
{{ form.name(class="form-control") }}
</div>
<div class="form-group">
<label for="password">Current Password</label>
<input type="password" class="form-control" name="confirm" id="confirm"/>
{{ form.confirm.label }}
{{ form.confirm(class="form-control") }}
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" id="password"/>
{{ form.password.label }}
{{ form.password(class="form-control") }}
</div>
<div class="form-group">
<label for="website">Website</label>
<input type="url" class="form-control" name="website" id="website"
{% if team is defined and team.website %}value="{{ team.website }}"{% endif %} />
{{ form.website.label }}
{{ form.website(class="form-control") }}
</div>
<div class="form-group">
<label for="affiliation">Affiliation</label>
<input type="text" class="form-control" name="affiliation" id="affiliation"
{% if team is defined and team.affiliation %}value="{{ team.affiliation }}"{% endif %} />
{{ form.affiliation.label }}
{{ form.affiliation(class="form-control") }}
</div>
<div class="form-group">
<label for="affiliation">Country</label>
<select class="form-control custom-select" id="country-input" name="country">
<option></option>
{% set countries = get_countries() %}
{% for country_code in countries.keys() %}
<option value="{{ country_code }}"{% if team is defined and team.country == country_code %} selected{% endif %}>
{{ countries[country_code] }}
</option>
{% endfor %}
</select>
{{ form.country.label }}
{{ form.country(class="form-control custom-select") }}
</div>
<div id="results">
</div>
<button id="update-team" type="submit"
class="btn btn-primary btn-outlined float-right modal-action">
Submit
</button>
{{ form.submit(class="btn btn-primary btn-outlined float-right modal-action") }}
</form>
{% endwith %}
</div>
</div>
</div>
@@ -73,28 +61,21 @@
</button>
</div>
<div class="modal-body clearfix">
{% with form = Forms.teams.TeamCaptainForm(captain_id=team.captain_id) %}
<form id="team-captain-form" method="POST">
<input type="hidden" name="id">
<div class="form-group">
<label for="captain">Team Captain</label>
<select class="form-control custom-select" id="captain" name="captain_id">
{% if team is defined %}
<option value="{{ team.captain.id }}">{{ team.captain.name }}</option>
{{ form.captain_id.label }}
{% for member in team.members %}
{% if member.id != team.captain.id %}
<option value="{{ member.id }}">{{ member.name }}</option>
{% endif %}
{# Append members to the select choices #}
{% set _ = form.captain_id.choices.append((member.id, member.name)) %}
{% endfor %}
{% endif %}
</select>
{{ form.captain_id(class="form-control custom-select") }}
</div>
<div id="results">
</div>
<button type="submit" class="btn btn-primary btn-outlined float-right modal-action">
Submit
</button>
{{ form.submit(class="btn btn-primary btn-outlined float-right modal-action") }}
</form>
{% endwith %}
</div>
</div>
</div>

View File

@@ -262,6 +262,9 @@ COUNTRIES_LIST = [
# Nicely titled (and translatable) country names.
COUNTRIES_DICT = OrderedDict(COUNTRIES_LIST)
# List of countries suitable for use in forms
SELECT_COUNTRIES_LIST = [("", "")] + COUNTRIES_LIST
def get_countries():
return COUNTRIES_DICT

View File

@@ -60,6 +60,7 @@ def init_template_globals(app):
from CTFd.constants.config import Configs
from CTFd.constants.plugins import Plugins
from CTFd.constants.sessions import Session
from CTFd.forms import Forms
app.jinja_env.globals.update(config=config)
app.jinja_env.globals.update(get_pages=get_pages)
@@ -94,6 +95,7 @@ def init_template_globals(app):
app.jinja_env.globals.update(Configs=Configs)
app.jinja_env.globals.update(Plugins=Plugins)
app.jinja_env.globals.update(Session=Session)
app.jinja_env.globals.update(Forms=Forms)
def init_logs(app):

View File

@@ -226,12 +226,7 @@ def setup():
cache.clear()
return redirect(url_for("views.static_html"))
return render_template(
"setup.html",
nonce=session.get("nonce"),
state=serialize(generate_nonce()),
themes=config.get_themes(),
)
return render_template("setup.html", state=serialize(generate_nonce()))
return redirect(url_for("views.static_html"))

View File

@@ -22,3 +22,4 @@ flask-marshmallow==0.10.1
marshmallow-sqlalchemy==0.17.0
boto3==1.13.9
marshmallow==2.20.2
WTForms==2.3.1

View File

@@ -277,7 +277,7 @@ def test_contact_for_password_reset():
forgot_link = "http://localhost/reset_password"
r = client.get(forgot_link)
assert "Contact a CTF organizer" in r.get_data(as_text=True)
assert "contact an organizer" in r.get_data(as_text=True)
destroy_ctfd(app)