mirror of
https://github.com/aljazceru/CTFd.git
synced 2025-12-17 14:04:20 +01:00
WIP: Add registration password (#1946)
* Closes #1895 * Add a registration password to account creation (ignoring SSO or API based account creation)
This commit is contained in:
@@ -197,6 +197,7 @@ def register():
|
||||
website = request.form.get("website")
|
||||
affiliation = request.form.get("affiliation")
|
||||
country = request.form.get("country")
|
||||
registration_code = request.form.get("registration_code", "")
|
||||
|
||||
name_len = len(name) == 0
|
||||
names = Users.query.add_columns("name", "id").filter_by(name=name).first()
|
||||
@@ -210,6 +211,13 @@ def register():
|
||||
valid_email = validators.validate_email(email_address)
|
||||
team_name_email_check = validators.validate_email(name)
|
||||
|
||||
if get_config("registration_code"):
|
||||
if (
|
||||
registration_code.lower()
|
||||
!= get_config("registration_code", default="").lower()
|
||||
):
|
||||
errors.append("The registration code you entered was incorrect")
|
||||
|
||||
# Process additional user fields
|
||||
fields = {}
|
||||
for field in UserFields.query.all():
|
||||
|
||||
@@ -4,7 +4,12 @@ from wtforms.validators import InputRequired
|
||||
|
||||
from CTFd.forms import BaseForm
|
||||
from CTFd.forms.fields import SubmitField
|
||||
from CTFd.forms.users import attach_custom_user_fields, build_custom_user_fields
|
||||
from CTFd.forms.users import (
|
||||
attach_custom_user_fields,
|
||||
attach_registration_code_field,
|
||||
build_custom_user_fields,
|
||||
build_registration_code_field,
|
||||
)
|
||||
|
||||
|
||||
def RegistrationForm(*args, **kwargs):
|
||||
@@ -18,9 +23,10 @@ def RegistrationForm(*args, **kwargs):
|
||||
def extra(self):
|
||||
return build_custom_user_fields(
|
||||
self, include_entries=False, blacklisted_items=()
|
||||
)
|
||||
) + build_registration_code_field(self)
|
||||
|
||||
attach_custom_user_fields(_RegistrationForm)
|
||||
attach_registration_code_field(_RegistrationForm)
|
||||
|
||||
return _RegistrationForm(*args, **kwargs)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ from wtforms import BooleanField, PasswordField, SelectField, StringField
|
||||
from wtforms.fields.html5 import EmailField
|
||||
from wtforms.validators import InputRequired
|
||||
|
||||
from CTFd.constants.config import Configs
|
||||
from CTFd.forms import BaseForm
|
||||
from CTFd.forms.fields import SubmitField
|
||||
from CTFd.models import UserFieldEntries, UserFields
|
||||
@@ -79,6 +80,36 @@ def attach_custom_user_fields(form_cls, **kwargs):
|
||||
setattr(form_cls, f"fields[{field.id}]", input_field)
|
||||
|
||||
|
||||
def build_registration_code_field(form_cls):
|
||||
"""
|
||||
Build the appropriate field so we can render it via the extra property.
|
||||
Add field_type so Jinja knows how to render it.
|
||||
"""
|
||||
if Configs.registration_code:
|
||||
field = getattr(form_cls, "registration_code") # noqa B009
|
||||
field.field_type = "text"
|
||||
return [field]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def attach_registration_code_field(form_cls):
|
||||
"""
|
||||
If we have a registration code required, we attach it to the form similar
|
||||
to attach_custom_user_fields
|
||||
"""
|
||||
if Configs.registration_code:
|
||||
setattr( # noqa B010
|
||||
form_cls,
|
||||
"registration_code",
|
||||
StringField(
|
||||
"Registration Code",
|
||||
description="Registration code required to create account",
|
||||
validators=[InputRequired()],
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class UserSearchForm(BaseForm):
|
||||
field = SelectField(
|
||||
"Search Field",
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link rounded-0" href="#settings" role="tab" data-toggle="tab">Settings</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link rounded-0" href="#security" role="tab" data-toggle="tab">Security</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link rounded-0" href="#email" role="tab" data-toggle="tab">Email</a>
|
||||
</li>
|
||||
@@ -73,6 +76,8 @@
|
||||
|
||||
{% include "admin/configs/settings.html" %}
|
||||
|
||||
{% include "admin/configs/security.html" %}
|
||||
|
||||
{% include "admin/configs/email.html" %}
|
||||
|
||||
{% include "admin/configs/time.html" %}
|
||||
|
||||
14
CTFd/themes/admin/templates/configs/security.html
Normal file
14
CTFd/themes/admin/templates/configs/security.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<div role="tabpanel" class="tab-pane config-section active" id="security">
|
||||
<form method="POST" autocomplete="off" class="w-100">
|
||||
<div class="form-group">
|
||||
<label for="ctf_name">
|
||||
Registration Code
|
||||
<small class="form-text text-muted">Registration Code required for account registration (SSO excluded)</small>
|
||||
</label>
|
||||
<input class="form-control" id='registration_code' name='registration_code' type='text' placeholder="Registration Code"
|
||||
{% if registration_code is defined and registration_code != None %}value="{{ registration_code }}"{% endif %}>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-md btn-primary float-right">Update</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -423,3 +423,44 @@ def test_banned_user():
|
||||
r = client.get(route)
|
||||
assert r.status_code == 403
|
||||
destroy_ctfd(app)
|
||||
|
||||
|
||||
def test_registration_code_required():
|
||||
"""
|
||||
Test that registration code configuration properly blocks logins
|
||||
with missing and incorrect registration codes
|
||||
"""
|
||||
app = create_ctfd()
|
||||
with app.app_context():
|
||||
# Set a registration code
|
||||
set_config("registration_code", "secret-sauce")
|
||||
|
||||
with app.test_client() as client:
|
||||
# Load CSRF nonce
|
||||
r = client.get("/register")
|
||||
resp = r.get_data(as_text=True)
|
||||
assert "Registration Code" in resp
|
||||
with client.session_transaction() as sess:
|
||||
data = {
|
||||
"name": "user",
|
||||
"email": "user1@examplectf.com",
|
||||
"password": "password",
|
||||
"nonce": sess.get("nonce"),
|
||||
}
|
||||
# Attempt registration without password
|
||||
r = client.post("/register", data=data)
|
||||
resp = r.get_data(as_text=True)
|
||||
assert "The registration code you entered was incorrect" in resp
|
||||
|
||||
# Attempt registration with wrong password
|
||||
data["registration_code"] = "wrong-sauce"
|
||||
r = client.post("/register", data=data)
|
||||
resp = r.get_data(as_text=True)
|
||||
assert "The registration code you entered was incorrect" in resp
|
||||
|
||||
# Attempt registration with right password
|
||||
data["registration_code"] = "secret-sauce"
|
||||
r = client.post("/register", data=data)
|
||||
assert r.status_code == 302
|
||||
assert r.location.startswith("http://localhost/challenges")
|
||||
destroy_ctfd(app)
|
||||
|
||||
Reference in New Issue
Block a user