From e06e34994e7b62db1bdf39a4aa4aeb5871f1a83c Mon Sep 17 00:00:00 2001 From: richtier Date: Thu, 12 Oct 2017 16:30:38 +0100 Subject: [PATCH] Skip caotcha validation twice --- company/forms.py | 1 + exportopportunity/forms.py | 6 ++++++ exportopportunity/tests/test_views.py | 15 +++++++++------ exportopportunity/views.py | 17 +++++++++++++++++ 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/company/forms.py b/company/forms.py index 6fe67d68..a0ec86e4 100644 --- a/company/forms.py +++ b/company/forms.py @@ -46,6 +46,7 @@ def clean_page(self): class ContactCompanyForm(forms.Form): + error_css_class = 'input-field-container has-error' TERMS_CONDITIONS_MESSAGE = ( 'Tick the box to confirm you agree to the terms and conditions.' diff --git a/exportopportunity/forms.py b/exportopportunity/forms.py index 04775e99..948057e7 100644 --- a/exportopportunity/forms.py +++ b/exportopportunity/forms.py @@ -190,6 +190,12 @@ class OpportunityNeedLegalForm(OpportunityNeedBaseForm): class OpportunityContactDetailsForm(forms.Form): + + def __init__(self, skip_captcha_errors=False, *args, **kwargs): + super().__init__(*args, **kwargs) + if skip_captcha_errors: + del self.fields['captcha'] + error_css_class = 'input-field-container has-error' MESSAGE_TERMS_CONDITIONS = ( 'Tick the box to confirm you agree to the terms and conditions.' diff --git a/exportopportunity/tests/test_views.py b/exportopportunity/tests/test_views.py index b8d154dc..e6f6a8f4 100644 --- a/exportopportunity/tests/test_views.py +++ b/exportopportunity/tests/test_views.py @@ -237,9 +237,10 @@ def test_campaign_language_switcher( @patch.object(views.helpers, 'get_showcase_companies', return_value=showcase_companies) @patch.object(views.api_client.exportopportunity, 'create_opportunity_food') +@patch('captcha.fields.ReCaptchaField.clean') def test_submit_export_opportunity_food( - mock_create_opportunity, mock_get_showcase_companies, client, - api_response_200, settings, captcha_stub, url, country + mock_clean_captcha, mock_create_opportunity, mock_get_showcase_companies, + client, api_response_200, settings, captcha_stub, url, country ): settings.FEATURE_EXPORT_OPPORTUNITY_LEAD_GENERATION_ENABLED = True mock_create_opportunity.return_value = api_response_200 @@ -296,7 +297,6 @@ def test_submit_export_opportunity_food( 'additional_requirements': 'give me things', 'business_model': ['distribution'], 'business_model_other': 'things', - 'captcha': None, 'company_name': 'Jim corp', 'company_website': 'http://www.example.com', 'contact_preference': ['EMAIL', 'PHONE'], @@ -321,6 +321,7 @@ def test_submit_export_opportunity_food( assert mock_get_showcase_companies.call_args == call( sector=sectors.FOOD_AND_DRINK ) + assert mock_clean_captcha.call_count == 1 @pytest.mark.parametrize('url,country', ( @@ -336,9 +337,10 @@ def test_submit_export_opportunity_food( @patch.object(views.helpers, 'get_showcase_companies', return_value=showcase_companies) @patch.object(views.api_client.exportopportunity, 'create_opportunity_legal') +@patch('captcha.fields.ReCaptchaField.clean') def test_submit_export_opportunity_legal( - mock_create_opportunity, mock_get_showcase_companies, client, - api_response_200, settings, captcha_stub, url, country + mock_clean_captcha, mock_create_opportunity, mock_get_showcase_companies, + client, api_response_200, settings, captcha_stub, url, country ): settings.FEATURE_EXPORT_OPPORTUNITY_LEAD_GENERATION_ENABLED = True mock_create_opportunity.return_value = api_response_200 @@ -390,7 +392,6 @@ def test_submit_export_opportunity_legal( assert mock_create_opportunity.call_args == call( form_data={ 'company_name': 'Jim corp', - 'captcha': None, 'full_name': 'jim example', 'phone_number': '07507605844', 'advice_type_other': 'things', @@ -414,3 +415,5 @@ def test_submit_export_opportunity_legal( assert mock_get_showcase_companies.call_args == call( campaign_tag=lead_generation.LEGAL_IS_GREAT, ) + + assert mock_clean_captcha.call_count == 1 diff --git a/exportopportunity/views.py b/exportopportunity/views.py index 3688b978..05d61b57 100644 --- a/exportopportunity/views.py +++ b/exportopportunity/views.py @@ -71,6 +71,8 @@ class BaseOpportunityWizardView( language_form_class = forms.LanguageLeadGeneartionForm + should_skip_captcha = False + def dispatch(self, *args, **kwargs): if not settings.FEATURE_EXPORT_OPPORTUNITY_LEAD_GENERATION_ENABLED: raise Http404() @@ -107,6 +109,21 @@ def done(self, *args, **kwargs): } ) + def render_done(self, *args, **kwargs): + # django-forms runs form.is_valid() for all steps after the final step + # meaning the same captcha code is sent to google multiple times. + # Google rejects the code the second time as it's already seen it and + # thinks the second is a "replay attack" - so prevent formtools from + # validating the captcha twice. + self.should_skip_captcha = True + return super().render_done(*args, **kwargs) + + def get_form_kwargs(self, step): + kwargs = super().get_form_kwargs(step=step) + if step == self.CONTACT and self.should_skip_captcha: + kwargs['skip_captcha_errors'] = True + return kwargs + class FoodIsGreatOpportunityWizardView(BaseOpportunityWizardView): form_list = (