mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-24 16:24:08 -04:00
Merge pull request #3966 from alphagov/block-plus-addressing
Be strict about similar email addresses when inviting a user to an emergency alerts service
This commit is contained in:
@@ -62,6 +62,7 @@ from app.models.roles_and_permissions import (
|
|||||||
roles,
|
roles,
|
||||||
)
|
)
|
||||||
from app.utils import merge_jsonlike
|
from app.utils import merge_jsonlike
|
||||||
|
from app.utils.user import distinct_email_addresses
|
||||||
|
|
||||||
|
|
||||||
def get_time_value_and_label(future_time):
|
def get_time_value_and_label(future_time):
|
||||||
@@ -1042,12 +1043,14 @@ class BroadcastPermissionsForm(BasePermissionsForm):
|
|||||||
class BaseInviteUserForm():
|
class BaseInviteUserForm():
|
||||||
email_address = email_address(gov_user=False)
|
email_address = email_address(gov_user=False)
|
||||||
|
|
||||||
def __init__(self, invalid_email_address, *args, **kwargs):
|
def __init__(self, inviter_email_address, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.invalid_email_address = invalid_email_address.lower()
|
self.inviter_email_address = inviter_email_address
|
||||||
|
|
||||||
def validate_email_address(self, field):
|
def validate_email_address(self, field):
|
||||||
if field.data.lower() == self.invalid_email_address and not current_user.platform_admin:
|
if current_user.platform_admin:
|
||||||
|
return
|
||||||
|
if field.data.lower() == self.inviter_email_address.lower():
|
||||||
raise ValidationError("You cannot send an invitation to yourself")
|
raise ValidationError("You cannot send an invitation to yourself")
|
||||||
|
|
||||||
|
|
||||||
@@ -1058,16 +1061,20 @@ class InviteUserForm(BaseInviteUserForm, PermissionsForm):
|
|||||||
class BroadcastInviteUserForm(BaseInviteUserForm, BroadcastPermissionsForm):
|
class BroadcastInviteUserForm(BaseInviteUserForm, BroadcastPermissionsForm):
|
||||||
email_address = email_address(gov_user=True)
|
email_address = email_address(gov_user=True)
|
||||||
|
|
||||||
|
def validate_email_address(self, field):
|
||||||
|
if not distinct_email_addresses(field.data, self.inviter_email_address):
|
||||||
|
raise ValidationError("You cannot send an invitation to yourself")
|
||||||
|
|
||||||
|
|
||||||
class InviteOrgUserForm(StripWhitespaceForm):
|
class InviteOrgUserForm(StripWhitespaceForm):
|
||||||
email_address = email_address(gov_user=False)
|
email_address = email_address(gov_user=False)
|
||||||
|
|
||||||
def __init__(self, invalid_email_address, *args, **kwargs):
|
def __init__(self, inviter_email_address, *args, **kwargs):
|
||||||
super(InviteOrgUserForm, self).__init__(*args, **kwargs)
|
super(InviteOrgUserForm, self).__init__(*args, **kwargs)
|
||||||
self.invalid_email_address = invalid_email_address.lower()
|
self.inviter_email_address = inviter_email_address.lower()
|
||||||
|
|
||||||
def validate_email_address(self, field):
|
def validate_email_address(self, field):
|
||||||
if field.data.lower() == self.invalid_email_address and not current_user.platform_admin:
|
if field.data.lower() == self.inviter_email_address and not current_user.platform_admin:
|
||||||
raise ValidationError("You cannot send an invitation to yourself")
|
raise ValidationError("You cannot send an invitation to yourself")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ def invite_user(service_id, user_id=None):
|
|||||||
form_class = InviteUserForm
|
form_class = InviteUserForm
|
||||||
|
|
||||||
form = form_class(
|
form = form_class(
|
||||||
invalid_email_address=current_user.email_address,
|
inviter_email_address=current_user.email_address,
|
||||||
all_template_folders=current_service.all_template_folders,
|
all_template_folders=current_service.all_template_folders,
|
||||||
folder_permissions=[f['id'] for f in current_service.all_template_folders]
|
folder_permissions=[f['id'] for f in current_service.all_template_folders]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ def manage_org_users(org_id):
|
|||||||
@user_has_permissions()
|
@user_has_permissions()
|
||||||
def invite_org_user(org_id):
|
def invite_org_user(org_id):
|
||||||
form = InviteOrgUserForm(
|
form = InviteOrgUserForm(
|
||||||
invalid_email_address=current_user.email_address
|
inviter_email_address=current_user.email_address
|
||||||
)
|
)
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
email_address = form.email_address.data
|
email_address = form.email_address.data
|
||||||
|
|||||||
@@ -66,3 +66,14 @@ def _email_address_ends_with(email_address, known_domains):
|
|||||||
))
|
))
|
||||||
for known in known_domains
|
for known in known_domains
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def normalise_email_address_aliases(email_address):
|
||||||
|
local_part, domain = email_address.split('@')
|
||||||
|
local_part = local_part.split('+')[0].replace('.', '')
|
||||||
|
|
||||||
|
return f'{local_part}@{domain}'.lower()
|
||||||
|
|
||||||
|
|
||||||
|
def distinct_email_addresses(*args):
|
||||||
|
return len(args) == len(set(map(normalise_email_address_aliases, args)))
|
||||||
|
|||||||
@@ -1443,6 +1443,70 @@ def test_user_cant_invite_themselves(
|
|||||||
assert not mock_create_invite.called
|
assert not mock_create_invite.called
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('email_address', (
|
||||||
|
'test@user.gov.uk',
|
||||||
|
'TEST@user.gov.uk',
|
||||||
|
'test@USER.gov.uk',
|
||||||
|
'test+test@user.gov.uk',
|
||||||
|
'te.st@user.gov.uk',
|
||||||
|
pytest.param('test2@user.gov.uk', marks=pytest.mark.xfail),
|
||||||
|
pytest.param('test@other.gov.uk', marks=pytest.mark.xfail),
|
||||||
|
))
|
||||||
|
def test_broadcast_user_cant_invite_themselves_or_their_aliases(
|
||||||
|
client_request,
|
||||||
|
service_one,
|
||||||
|
mocker,
|
||||||
|
active_user_with_permissions,
|
||||||
|
mock_create_invite,
|
||||||
|
mock_get_template_folders,
|
||||||
|
email_address,
|
||||||
|
):
|
||||||
|
service_one['permissions'] += ['broadcast']
|
||||||
|
page = client_request.post(
|
||||||
|
'main.invite_user',
|
||||||
|
service_id=SERVICE_ONE_ID,
|
||||||
|
_data={
|
||||||
|
'email_address': email_address,
|
||||||
|
'permissions_field': []
|
||||||
|
},
|
||||||
|
_expected_status=200,
|
||||||
|
)
|
||||||
|
assert normalize_spaces(page.select_one('span.govuk-error-message').text) == (
|
||||||
|
"Error: You cannot send an invitation to yourself"
|
||||||
|
)
|
||||||
|
assert mock_create_invite.called is False
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('extra_service_permissions', (
|
||||||
|
pytest.param([], marks=pytest.mark.xfail),
|
||||||
|
['broadcast'],
|
||||||
|
))
|
||||||
|
def test_platform_admin_cant_invite_themselves_to_broadcast_services(
|
||||||
|
client_request,
|
||||||
|
service_one,
|
||||||
|
mocker,
|
||||||
|
platform_admin_user,
|
||||||
|
mock_create_invite,
|
||||||
|
mock_get_template_folders,
|
||||||
|
extra_service_permissions,
|
||||||
|
):
|
||||||
|
service_one['permissions'] += extra_service_permissions
|
||||||
|
client_request.login(platform_admin_user)
|
||||||
|
page = client_request.post(
|
||||||
|
'main.invite_user',
|
||||||
|
service_id=SERVICE_ONE_ID,
|
||||||
|
_data={
|
||||||
|
'email_address': platform_admin_user['email_address'],
|
||||||
|
'permissions_field': []
|
||||||
|
},
|
||||||
|
_expected_status=200,
|
||||||
|
)
|
||||||
|
assert normalize_spaces(page.select_one('span.govuk-error-message').text) == (
|
||||||
|
"Error: You cannot send an invitation to yourself"
|
||||||
|
)
|
||||||
|
assert mock_create_invite.called is False
|
||||||
|
|
||||||
|
|
||||||
def test_no_permission_manage_users_page(
|
def test_no_permission_manage_users_page(
|
||||||
client_request,
|
client_request,
|
||||||
service_one,
|
service_one,
|
||||||
|
|||||||
Reference in New Issue
Block a user