diff --git a/app/user/rest.py b/app/user/rest.py index 87e9cf305..b4011ebe7 100644 --- a/app/user/rest.py +++ b/app/user/rest.py @@ -196,7 +196,7 @@ def send_user_email_code(user_to_send_to, data): secret_code = str(uuid.uuid4()) personalisation = { 'name': user_to_send_to.name, - 'url': _create_2fa_url(user_to_send_to, secret_code, data.get('next')) + 'url': _create_2fa_url(user_to_send_to, secret_code, data.get('next'), data.get('email_auth_link_host')) } create_2fa_code( @@ -413,10 +413,10 @@ def _create_confirmation_url(user, email_address): return url_with_token(data, url, current_app.config) -def _create_2fa_url(user, secret_code, next_redir): +def _create_2fa_url(user, secret_code, next_redir, email_auth_link_host): data = json.dumps({'user_id': str(user.id), 'secret_code': secret_code}) url = '/email-auth/' - ret = url_with_token(data, url, current_app.config) + ret = url_with_token(data, url, current_app.config, base_url=email_auth_link_host) if next_redir: ret += '?{}'.format(urlencode({'next': next_redir})) return ret diff --git a/app/user/users_schema.py b/app/user/users_schema.py index 4f4b27f8c..cc8bb1040 100644 --- a/app/user/users_schema.py +++ b/app/user/users_schema.py @@ -22,6 +22,7 @@ post_send_user_email_code_schema = { # doesn't need 'to' as we'll just grab user.email_address. but lets keep it # as allowed to keep admin code cleaner, but only as null to prevent confusion 'to': {'type': 'null'}, + 'email_auth_link_host': {'type': ['string', 'null']}, 'next': {'type': ['string', 'null']}, }, 'required': [], diff --git a/app/utils.py b/app/utils.py index 49f6d61dc..b1367cc7d 100644 --- a/app/utils.py +++ b/app/utils.py @@ -20,10 +20,10 @@ def pagination_links(pagination, endpoint, **kwargs): return links -def url_with_token(data, url, config): +def url_with_token(data, url, config, base_url=None): from notifications_utils.url_safe_token import generate_token token = generate_token(data, config['SECRET_KEY'], config['DANGEROUS_SALT']) - base_url = config['ADMIN_BASE_URL'] + url + base_url = (base_url or config['ADMIN_BASE_URL']) + url return base_url + token diff --git a/tests/app/user/test_rest_verify.py b/tests/app/user/test_rest_verify.py index c43507784..b97f4ef81 100644 --- a/tests/app/user/test_rest_verify.py +++ b/tests/app/user/test_rest_verify.py @@ -343,12 +343,30 @@ def test_reset_failed_login_count_returns_404_when_user_does_not_exist(client): assert resp.status_code == 404 -def test_send_user_email_code(admin_request, mocker, sample_user, email_2fa_code_template): +@pytest.mark.parametrize('data, expected_auth_url', ( + ( + {}, + 'http://localhost:6012/email-auth/.', + ), + ( + {'to': None}, + 'http://localhost:6012/email-auth/.', + ), + ( + {'to': None, 'email_auth_link_host': 'https://example.com'}, + 'https://example.com/email-auth/.', + ), +)) +def test_send_user_email_code( + admin_request, + mocker, + sample_user, + email_2fa_code_template, + data, + expected_auth_url, +): deliver_email = mocker.patch('app.celery.provider_tasks.deliver_email.apply_async') - data = { - 'to': None - } admin_request.post( 'user.send_user_2fa_code', code_type='email', @@ -361,6 +379,7 @@ def test_send_user_email_code(admin_request, mocker, sample_user, email_2fa_code assert noti.to == sample_user.email_address assert str(noti.template_id) == current_app.config['EMAIL_2FA_TEMPLATE_ID'] assert noti.personalisation['name'] == 'Test User' + assert noti.personalisation['url'].startswith(expected_auth_url) deliver_email.assert_called_once_with( [str(noti.id)], queue='notify-internal-tasks'