mirror of
https://github.com/aljazceru/CTFd.git
synced 2025-12-17 05:54:19 +01:00
Add email whitelist wildcard (#2375)
* add wildcard for email whitelisting --------- Co-authored-by: Kevin Chung <kchung@ctfd.io>
This commit is contained in:
@@ -31,7 +31,7 @@ class ResetInstanceForm(BaseForm):
|
|||||||
class AccountSettingsForm(BaseForm):
|
class AccountSettingsForm(BaseForm):
|
||||||
domain_whitelist = StringField(
|
domain_whitelist = StringField(
|
||||||
"Account Email Whitelist",
|
"Account Email Whitelist",
|
||||||
description="Comma-seperated email domains which users can register under (e.g. ctfd.io, gmail.com, yahoo.com)",
|
description="Comma-seperated email domains which users can register under (e.g. ctfd.io, example.com, *.example.com)",
|
||||||
)
|
)
|
||||||
team_creation = SelectField(
|
team_creation = SelectField(
|
||||||
"Team Creation",
|
"Team Creation",
|
||||||
|
|||||||
@@ -137,8 +137,26 @@ def user_created_notification(addr, name, password):
|
|||||||
def check_email_is_whitelisted(email_address):
|
def check_email_is_whitelisted(email_address):
|
||||||
local_id, _, domain = email_address.partition("@")
|
local_id, _, domain = email_address.partition("@")
|
||||||
domain_whitelist = get_config("domain_whitelist")
|
domain_whitelist = get_config("domain_whitelist")
|
||||||
|
|
||||||
if domain_whitelist:
|
if domain_whitelist:
|
||||||
domain_whitelist = [d.strip() for d in domain_whitelist.split(",")]
|
domain_whitelist = [d.strip() for d in domain_whitelist.split(",")]
|
||||||
if domain not in domain_whitelist:
|
|
||||||
return False
|
for allowed_domain in domain_whitelist:
|
||||||
|
if allowed_domain.startswith("*."):
|
||||||
|
# domains should never container the "*" char
|
||||||
|
if "*" in domain:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Handle wildcard domain case
|
||||||
|
suffix = allowed_domain[1:] # Remove the "*" prefix
|
||||||
|
if domain.endswith(suffix):
|
||||||
|
return True
|
||||||
|
|
||||||
|
elif domain == allowed_domain:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# whitelist is specified but the email doesn't match any domains
|
||||||
|
return False
|
||||||
|
|
||||||
|
# whitelist is not specified - allow all emails
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from freezegun import freeze_time
|
|||||||
|
|
||||||
from CTFd.utils import get_config, set_config
|
from CTFd.utils import get_config, set_config
|
||||||
from CTFd.utils.email import (
|
from CTFd.utils.email import (
|
||||||
|
check_email_is_whitelisted,
|
||||||
sendmail,
|
sendmail,
|
||||||
successful_registration_notification,
|
successful_registration_notification,
|
||||||
verify_email_address,
|
verify_email_address,
|
||||||
@@ -239,3 +240,82 @@ def test_successful_registration_email(mock_smtp):
|
|||||||
email_msg
|
email_msg
|
||||||
)
|
)
|
||||||
destroy_ctfd(app)
|
destroy_ctfd(app)
|
||||||
|
|
||||||
|
|
||||||
|
def test_email_whitelist():
|
||||||
|
app = create_ctfd()
|
||||||
|
with app.app_context():
|
||||||
|
set_config("domain_whitelist", "example.com")
|
||||||
|
test_cases_specific_domain = [
|
||||||
|
("john.doe@example.com", True),
|
||||||
|
("john.doe@ext.example.com", False),
|
||||||
|
("john.doe@example.io", False),
|
||||||
|
("john.doe@example.co", False),
|
||||||
|
("john.doe@ample.com", False),
|
||||||
|
("john.doe@exexample.com", False),
|
||||||
|
]
|
||||||
|
|
||||||
|
for case in test_cases_specific_domain:
|
||||||
|
email, expected = case
|
||||||
|
assert check_email_is_whitelisted(email) is expected
|
||||||
|
|
||||||
|
set_config("domain_whitelist", "*.example.com")
|
||||||
|
test_cases_wildcard_domain = [
|
||||||
|
("john.doe@ext.example.com", True),
|
||||||
|
("john.doe@.example.com", True), # this is expected behaviour
|
||||||
|
("john.doe@example.com", False),
|
||||||
|
("john.doe@example.io", False),
|
||||||
|
("john.doe@example.co", False),
|
||||||
|
("john.doe@ample.com", False),
|
||||||
|
("john.doe@exexample.com", False),
|
||||||
|
("john.doe@*example.com", False),
|
||||||
|
("john.doe@*.example.com", False),
|
||||||
|
]
|
||||||
|
|
||||||
|
for case in test_cases_wildcard_domain:
|
||||||
|
email, expected = case
|
||||||
|
assert check_email_is_whitelisted(email) is expected
|
||||||
|
|
||||||
|
set_config("domain_whitelist", "example.com, *.example.com")
|
||||||
|
test_cases_combined_domain = [
|
||||||
|
("john.doe@example.com", True),
|
||||||
|
("john.doe@ext.example.com", True),
|
||||||
|
("john.doe@.example.com", True), # this is expected behaviour
|
||||||
|
("john.doe@example.io", False),
|
||||||
|
("john.doe@example.co", False),
|
||||||
|
("john.doe@gmail.com", False),
|
||||||
|
("john.doe@ample.com", False),
|
||||||
|
("john.doe@exexample.com", False),
|
||||||
|
("john.doe@*example.com", False),
|
||||||
|
("john.doe@*.example.com", False),
|
||||||
|
]
|
||||||
|
|
||||||
|
for case in test_cases_combined_domain:
|
||||||
|
email, expected = case
|
||||||
|
assert check_email_is_whitelisted(email) is expected
|
||||||
|
|
||||||
|
set_config("domain_whitelist", "example.com, uni.acme.com, *.edu, *.edu.de")
|
||||||
|
|
||||||
|
test_cases_multiple_combined_domains = [
|
||||||
|
("john.doe@example.com", True),
|
||||||
|
("john.doe@uni.acme.com", True),
|
||||||
|
("john.doe@uni.edu", True),
|
||||||
|
("john.doe@cs.uni.edu", True),
|
||||||
|
("john.doe@mail.cs.uni.edu", True),
|
||||||
|
("john.doe@uni.edu.de", True),
|
||||||
|
("john.doe@cs.uni.edu.de", True),
|
||||||
|
("john.doe@mail.cs.uni.edu.de", True),
|
||||||
|
("john.doe@gmail.com", False),
|
||||||
|
("john.doe@ample.com", False),
|
||||||
|
("john.doe@example1.com", False),
|
||||||
|
("john.doe@1example.com", False),
|
||||||
|
("john.doe@ext.example.com", False),
|
||||||
|
("john.doe@cs.acme.com", False),
|
||||||
|
("john.doe@edu.com", False),
|
||||||
|
("john.doe@mail.uni.acme.com", False),
|
||||||
|
("john.doe@edu", False),
|
||||||
|
]
|
||||||
|
|
||||||
|
for case in test_cases_multiple_combined_domains:
|
||||||
|
email, expected = case
|
||||||
|
assert check_email_is_whitelisted(email) is expected
|
||||||
|
|||||||
Reference in New Issue
Block a user