mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-06 03:13:42 -05:00
We don’t want a single person to have two accounts on an emergency alerts service because it would let them circumvent the two eyes approval process. We can go some way to mitigating against this by stopping people using common methods that email providers use to alias email addresses. These are: - being case insensitive - being insensitive to the position or number of dots in the local part of an email address - using ‘plus addressing’ We already prevent the first one, this commit adds normalisation which strip out the second two before doing the comparision with the current user’s email address.
80 lines
2.2 KiB
Python
80 lines
2.2 KiB
Python
import os
|
|
from functools import wraps
|
|
|
|
from flask import abort, current_app
|
|
from flask_login import current_user, login_required
|
|
|
|
from app.notify_client.organisations_api_client import organisations_client
|
|
|
|
user_is_logged_in = login_required
|
|
|
|
|
|
with open('{}/email_domains.txt'.format(
|
|
os.path.dirname(os.path.realpath(__file__))
|
|
)) as email_domains:
|
|
GOVERNMENT_EMAIL_DOMAIN_NAMES = [line.strip() for line in email_domains]
|
|
|
|
|
|
def user_has_permissions(*permissions, **permission_kwargs):
|
|
def wrap(func):
|
|
@wraps(func)
|
|
def wrap_func(*args, **kwargs):
|
|
if not current_user.is_authenticated:
|
|
return current_app.login_manager.unauthorized()
|
|
if not current_user.has_permissions(*permissions, **permission_kwargs):
|
|
abort(403)
|
|
return func(*args, **kwargs)
|
|
return wrap_func
|
|
return wrap
|
|
|
|
|
|
def user_is_gov_user(f):
|
|
@wraps(f)
|
|
def wrapped(*args, **kwargs):
|
|
if not current_user.is_authenticated:
|
|
return current_app.login_manager.unauthorized()
|
|
if not current_user.is_gov_user:
|
|
abort(403)
|
|
return f(*args, **kwargs)
|
|
return wrapped
|
|
|
|
|
|
def user_is_platform_admin(f):
|
|
@wraps(f)
|
|
def wrapped(*args, **kwargs):
|
|
if not current_user.is_authenticated:
|
|
return current_app.login_manager.unauthorized()
|
|
if not current_user.platform_admin:
|
|
abort(403)
|
|
return f(*args, **kwargs)
|
|
return wrapped
|
|
|
|
|
|
def is_gov_user(email_address):
|
|
return _email_address_ends_with(
|
|
email_address, GOVERNMENT_EMAIL_DOMAIN_NAMES
|
|
) or _email_address_ends_with(
|
|
email_address, organisations_client.get_domains()
|
|
)
|
|
|
|
|
|
def _email_address_ends_with(email_address, known_domains):
|
|
return any(
|
|
email_address.lower().endswith((
|
|
"@{}".format(known),
|
|
".{}".format(known),
|
|
))
|
|
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)))
|