diff --git a/app/config.py b/app/config.py index dce3d4104..125b91834 100644 --- a/app/config.py +++ b/app/config.py @@ -42,6 +42,7 @@ class Config(object): 'nhs': 25000, } EMAIL_EXPIRY_SECONDS = 3600 # 1 hour + INVITATION_EXPIRY_SECONDS = 3600 * 24 * 2 # 2 days - also set on api HEADER_COLOUR = '#FFBF47' # $yellow HTTP_PROTOCOL = 'http' MAX_FAILED_LOGIN_COUNT = 10 diff --git a/app/main/views/invites.py b/app/main/views/invites.py index af3d0eede..4f1c88f7a 100644 --- a/app/main/views/invites.py +++ b/app/main/views/invites.py @@ -7,6 +7,7 @@ from flask import ( abort, current_app ) +from itsdangerous import SignatureExpired from markupsafe import Markup from notifications_utils.url_safe_token import check_token from flask_login import current_user @@ -21,12 +22,20 @@ from app import ( @main.route("/invitation/") def accept_invite(token): - check_token( - token, - current_app.config['SECRET_KEY'], - current_app.config['DANGEROUS_SALT'], - current_app.config['EMAIL_EXPIRY_SECONDS'] - ) + try: + check_token( + token, + current_app.config['SECRET_KEY'], + current_app.config['DANGEROUS_SALT'], + current_app.config['INVITATION_EXPIRY_SECONDS'] + ) + except SignatureExpired: + errors = [ + 'Your invitation to GOV.UK Notify has expired. ' + 'Please ask the person that invited you to send you another one' + ] + return render_template("error/400.html", message=errors), 400 + invited_user = invite_api_client.check_token(token) if not current_user.is_anonymous and current_user.email_address != invited_user.email_address: diff --git a/tests/app/main/views/test_accept_invite.py b/tests/app/main/views/test_accept_invite.py index fe4058f66..fd1f28924 100644 --- a/tests/app/main/views/test_accept_invite.py +++ b/tests/app/main/views/test_accept_invite.py @@ -1,6 +1,7 @@ from flask import url_for from bs4 import BeautifulSoup from unittest.mock import ANY +from itsdangerous import SignatureExpired import app @@ -368,3 +369,21 @@ def test_new_invited_user_verifies_and_added_to_service( raw_html = response.data.decode('utf-8') page = BeautifulSoup(raw_html, 'html.parser') assert page.find('h1').text == 'Dashboard' + + +def test_gives_message_if_token_has_expired( + app_, + client, + mock_check_invite_token, + mocker, +): + check_token = mocker.patch('app.main.views.invites.check_token', side_effect=SignatureExpired('this is too old')) + + response = client.get(url_for('main.accept_invite', token='a really old token')) + raw_html = response.data.decode('utf-8') + page = BeautifulSoup(raw_html, 'html.parser') + + check_token.assert_called_once_with(ANY, ANY, ANY, 3600 * 24 * 2) + assert response.status_code == 400 + assert 'Your invitation to GOV.UK Notify has expired' in page.find('h1').text + assert not mock_check_invite_token.called