Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions app/controllers/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,19 @@ def register_post():
name = request.form.get('name', '')
email = request.form.get('email', '').lower()
password = request.form.get('password', '')
password_verify = request.form.get('password_verify', '')

# Validate required fields
if not name or not email or not password:
missing = 'name' if not name else ('email' if not email else 'password')
if not name or not email or not password or not password_verify:
missing = ('name' if not name else 'email' if not email else
'password' if not password else 'password_verify')
flash(f'Field missing: {missing}', FLASH_ERROR)
return render_template('register/register.html', name=name, email=email)

if password != password_verify:
flash('Passwords do not match', FLASH_ERROR)
return render_template('register/register.html', name=name, email=email)

# Validate reCAPTCHA
if not verify_recaptcha(request):
flash('reCAPTCHA invalid!', FLASH_ERROR)
Expand Down
8 changes: 4 additions & 4 deletions templates/register/register.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,31 @@
<label class="form-label" for="name">Username</label>
</div>
<div class="col-9 col-sm-12">
<input class="form-input" type="text" name="name" id="name" placeholder="Name">
<input class="form-input" type="text" name="name" id="name" placeholder="Name" required>
</div>
</div>
<div class="form-group">
<div class="col-3 col-sm-12">
<label class="form-label" for="email">Email</label>
</div>
<div class="col-9 col-sm-12">
<input class="form-input" type="email" id="email" name="email" placeholder="email">
<input class="form-input" type="email" id="email" name="email" placeholder="email" required>
</div>
</div>
<div class="form-group">
<div class="col-3 col-sm-12">
<label class="form-label" for="password">Password</label>
</div>
<div class="col-9 col-sm-12">
<input class="form-input" type="password" id="password" name="password" placeholder="password">
<input class="form-input" type="password" id="password" name="password" placeholder="password" required>
</div>
</div>
<div class="form-group">
<div class="col-3 col-sm-12">
<label class="form-label" for="password_verify">Verify Password</label>
</div>
<div class="col-9 col-sm-12">
<input class="form-input" type="password" id="password_verify" name="password_verify" placeholder="password">
<input class="form-input" type="password" id="password_verify" name="password_verify" placeholder="password" required>
</div>
</div>
{% if RECAPTCHA_SITEKEY %}
Expand Down
13 changes: 10 additions & 3 deletions tests/test_controller_edge_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ def test_login_database_failure_is_generic(client):
def test_registration_rejects_duplicate_email_and_username(client, alice):
duplicate_email = client.post('/register', data={
'name': 'different', 'email': 'alice@example.test', 'password': 'password123',
'password_verify': 'password123',
})
duplicate_name = client.post('/register', data={
'name': 'alice', 'email': 'different@example.test', 'password': 'password123',
'password_verify': 'password123',
})
assert b'Account already exists' in duplicate_email.data
assert b'Account already exists' in duplicate_name.data
Expand All @@ -56,11 +58,11 @@ def test_registration_cross_field_conflicts(client, db):
})
username_is_email = client.post('/register', data={
'name': 'existing-email@example.test', 'email': 'new@example.test',
'password': 'password123',
'password': 'password123', 'password_verify': 'password123',
})
email_is_username = client.post('/register', data={
'name': 'new-user', 'email': 'existing@example.test',
'password': 'password123',
'password': 'password123', 'password_verify': 'password123',
})
assert b'username is not available' in username_is_email.data
assert b'email is not available' in email_is_username.data
Expand All @@ -69,17 +71,22 @@ def test_registration_cross_field_conflicts(client, db):
def test_registration_rejects_invalid_chars_and_recaptcha(client):
invalid = client.post('/register', data={
'name': 'bad name', 'email': 'valid@example.test', 'password': 'password123',
'password_verify': 'password123',
})
with patch('app.controllers.register.verify_recaptcha', return_value=False):
captcha = client.post('/register', data={
'name': 'valid', 'email': 'valid@example.test', 'password': 'password123',
'password_verify': 'password123',
})
assert b'Non allowed chars' in invalid.data
assert b'reCAPTCHA invalid' in captcha.data


def test_registration_hash_and_create_failures(client):
data = {'name': 'newuser', 'email': 'new@example.test', 'password': 'password123'}
data = {
'name': 'newuser', 'email': 'new@example.test',
'password': 'password123', 'password_verify': 'password123',
}
with patch('app.controllers.register.hash_string', side_effect=RuntimeError):
hashing = client.post('/register', data=data)
with patch('app.controllers.register.user_create', side_effect=RuntimeError):
Expand Down
22 changes: 22 additions & 0 deletions tests/test_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def test_registration_creates_a_user(client, db):
'name': 'charlie',
'email': 'CHARLIE@example.test',
'password': 'charlie-password',
'password_verify': 'charlie-password',
})

assert response.status_code == 302
Expand All @@ -75,6 +76,27 @@ def test_registration_creates_a_user(client, db):
assert match_string(user['password'], 'charlie-password') is True


def test_registration_requires_matching_password_confirmation(client, db):
registration = {
'name': 'charlie',
'email': 'charlie@example.test',
'password': 'charlie-password',
}

missing = client.post('/register', data=registration)
assert missing.status_code == 200
assert b'Field missing: password_verify' in missing.data
assert db.user.find_one({'name': 'charlie'}) is None

mismatch = client.post('/register', data={
**registration,
'password_verify': 'different-password',
})
assert mismatch.status_code == 200
assert b'Passwords do not match' in mismatch.data
assert db.user.find_one({'name': 'charlie'}) is None


def test_logout_clears_only_main_auth(alice_client):
with alice_client.session_transaction() as session:
session['unrelated'] = 'preserved'
Expand Down
Loading