From c7b6e6d9a552356853c30bf774956cab207b0bc2 Mon Sep 17 00:00:00 2001 From: Guillaume Risbourg Date: Fri, 16 Oct 2020 10:25:27 +0200 Subject: [PATCH] [bp] Fix transfer with certicode+ --- modules/bp/browser.py | 43 ++++++++++++++++++++++-------------- modules/bp/module.py | 2 ++ modules/bp/pages/__init__.py | 4 ++-- modules/bp/pages/transfer.py | 14 ++++++++++-- 4 files changed, 43 insertions(+), 20 deletions(-) diff --git a/modules/bp/browser.py b/modules/bp/browser.py index 9ad1d1a068..523e6391b8 100644 --- a/modules/bp/browser.py +++ b/modules/bp/browser.py @@ -53,7 +53,7 @@ SubscriptionPage, DownloadPage, ProSubscriptionPage, RevolvingAttributesPage, TwoFAPage, Validated2FAPage, SmsPage, DecoupledPage, HonorTransferPage, - RecipientSubmitDevicePage, OtpErrorPage, + CerticodePlusSubmitDevicePage, OtpErrorPage, ) from .pages.accounthistory import ( LifeInsuranceInvest, LifeInsuranceHistory, LifeInsuranceHistoryInv, RetirementHistory, @@ -281,8 +281,8 @@ class BPBrowser(LoginBrowser, StatesMixin): r'/voscomptes/canalXHTML/virement/virementSafran_sepa/confirmerInformations-virementSepa.ea', r'/voscomptes/canalXHTML/virement/virementSafran_national/valider-creerVirementNational.ea', r'/voscomptes/canalXHTML/virement/virementSafran_national/validerVirementNational-virementNational.ea', - # the following url is already used in transfer_summary - # but we need it to detect the case where the website displaies the list of devices + # The following url is already used in transfer_summary + # but we need it to detect the case where the website displays the list of devices # when a transfer is made with an otp or decoupled r'/voscomptes/canalXHTML/virement/virementSafran_sepa/confirmer-creerVirementSepa.ea', TransferConfirm @@ -301,9 +301,9 @@ class BPBrowser(LoginBrowser, StatesMixin): r'/voscomptes/canalXHTML/virement/mpiGestionBeneficiairesVirementsCreationBeneficiaire/valider-creationBeneficiaire.ea', ValidateRecipient ) - recipient_submit_device = URL( + certicode_plus_submit_device = URL( r'/voscomptes/canalXHTML/securisation/mpin/demandeCreation-securisationMPIN.ea', - RecipientSubmitDevicePage + CerticodePlusSubmitDevicePage ) rcpt_code = URL( r'/voscomptes/canalXHTML/virement/mpiGestionBeneficiairesVirementsCreationBeneficiaire/validerRecapBeneficiaire-creationBeneficiaire.ea', @@ -842,15 +842,26 @@ def execute_transfer(self, transfer): # If we just validated a code we land on transfer_summary. # If we just initiated the transfer we land on transfer_confirm. if self.transfer_confirm.is_here(): - # This will send a sms if a certicode validation is needed + # This will send a sms or an app validation if a certicode + # or certicode+ validation is needed. self.page.confirm() - if self.transfer_confirm.is_here() and self.page.is_certicode_needed(): + if self.transfer_confirm.is_here(): self.need_reload_state = True - self.sms_form = self.page.get_sms_form() - raise TransferStep( - transfer, - Value('code', label='Veuillez saisir le code de validation reçu par SMS'), - ) + if self.page.is_certicode_needed(): + self.sms_form = self.page.get_sms_form() + raise TransferStep( + transfer, + Value('code', label='Veuillez saisir le code de validation reçu par SMS'), + ) + elif self.page.is_certicode_plus_needed(): + device_choice_url = self.page.get_device_choice_url() + self.location(device_choice_url) + self.certicode_plus_submit_device.go(params={'deviceSelected': 0}) + message = self.page.get_app_validation_message() + raise AppValidation( + resource=transfer, + message=message, + ) return self.page.handle_response(transfer) @@ -879,7 +890,7 @@ def post_code(self, code): return True - def end_new_recipient_with_polling(self, recipient): + def end_with_polling(self, obj): polling_url = self.absurl( '/voscomptes/canalXHTML/securisation/mpin/validerOperation-securisationMPIN.ea', base=True @@ -889,7 +900,7 @@ def end_new_recipient_with_polling(self, recipient): '/voscomptes/canalXHTML/securisation/mpin/operationSucces-securisationMPIN.ea', base=True )) - return recipient + return obj @need_login def init_new_recipient(self, recipient, is_bp_account=False, **params): @@ -914,7 +925,7 @@ def init_new_recipient(self, recipient, is_bp_account=False, **params): self.location(device_choice_url) # force to use the first device like in the login to receive notification # this url send mobile notification - self.recipient_submit_device.go(params={'deviceSelected': 0}) + self.certicode_plus_submit_device.go(params={'deviceSelected': 0}) # Can do transfer to these recipient 48h after recipient.enabled_at = datetime.now().replace(microsecond=0) + timedelta(days=2) @@ -928,7 +939,7 @@ def init_new_recipient(self, recipient, is_bp_account=False, **params): def new_recipient(self, recipient, is_bp_account=False, **params): if params.get('resume') or self.resume: # Case of mobile app validation - return self.end_new_recipient_with_polling(recipient) + return self.end_with_polling(recipient) if 'code' in params: # Case of SMS OTP diff --git a/modules/bp/module.py b/modules/bp/module.py index a1c32da6f2..752b7815a8 100644 --- a/modules/bp/module.py +++ b/modules/bp/module.py @@ -108,6 +108,8 @@ def init_transfer(self, transfer, **params): return self.browser.validate_transfer_eligibility(transfer, **params) elif 'code' in params: return self.browser.validate_transfer_code(transfer, params['code']) + elif 'resume' in params: + return self.browser.end_with_polling(transfer) self.logger.info('Going to do a new transfer') account = strict_find_object(self.iter_accounts(), iban=transfer.account_iban) diff --git a/modules/bp/pages/__init__.py b/modules/bp/pages/__init__.py index a2ad2d3bc3..2423993f02 100644 --- a/modules/bp/pages/__init__.py +++ b/modules/bp/pages/__init__.py @@ -29,7 +29,7 @@ TransferChooseAccounts, CompleteTransfer, TransferConfirm, TransferSummary, CreateRecipient, ValidateRecipient, ValidateCountry, ConfirmPage, RcptSummary, - HonorTransferPage, RecipientSubmitDevicePage, + HonorTransferPage, CerticodePlusSubmitDevicePage, OtpErrorPage, ) from .subscription import SubscriptionPage, DownloadPage, ProSubscriptionPage @@ -40,5 +40,5 @@ 'AccountDesactivate', 'TransferChooseAccounts', 'CompleteTransfer', 'TransferConfirm', 'TransferSummary', 'UnavailablePage', 'CardsList', 'AccountRIB', 'Advisor', 'CreateRecipient', 'ValidateRecipient', 'ValidateCountry', 'ConfirmPage', 'RcptSummary', 'SubscriptionPage', 'DownloadPage', 'ProSubscriptionPage', 'RevolvingAttributesPage', 'Validated2FAPage', 'TwoFAPage', - 'SmsPage', 'DecoupledPage', 'HonorTransferPage', 'RecipientSubmitDevicePage', 'OtpErrorPage', + 'SmsPage', 'DecoupledPage', 'HonorTransferPage', 'CerticodePlusSubmitDevicePage', 'OtpErrorPage', ] diff --git a/modules/bp/pages/transfer.py b/modules/bp/pages/transfer.py index 9410cae980..a837acf656 100644 --- a/modules/bp/pages/transfer.py +++ b/modules/bp/pages/transfer.py @@ -224,6 +224,16 @@ def is_here(self): def is_certicode_needed(self): return CleanText('//div[contains(text(), "veuillez saisir votre code de validation reçu par SMS")]')(self.doc) + def is_certicode_plus_needed(self): + return CleanText('//script[contains(text(), "popupChoixDevice")]')(self.doc) + + def get_device_choice_url(self): + device_choice_popup_js = CleanText('//script[contains(text(), "popupChoixDevice")]')(self.doc) + if device_choice_popup_js: + device_choice_url = re.search(r'(?<=urlPopin = )\"(.*popUpDeviceChoice\.jsp)\";', device_choice_popup_js) + if device_choice_url: + return device_choice_url.group(1) + def get_sms_form(self): form = self.get_form(name='SaisieOTP') # Confirmation url is relative to the current page. We need to @@ -414,7 +424,7 @@ def get_error(self): return CleanText('//form//span[@class="warning" or @class="app_erreur"]')(self.doc) -class RecipientSubmitDevicePage(LoggedPage, MyHTMLPage): +class CerticodePlusSubmitDevicePage(LoggedPage, MyHTMLPage): def get_app_validation_message(self): # Mobile app message is too long, like this: # """ Une notification vous a été envoyée sur l’appareil que vous avez choisi: [PHONE]. @@ -426,7 +436,7 @@ def get_app_validation_message(self): app_validation_message = CleanText( '//main[@id="main"]//div[contains(text(), "Une notification vous a")]' )(self.doc) - assert app_validation_message, 'The notification message for new recipient is missing' + assert app_validation_message, 'The notification message is missing' msg_first_part = re.search(r'(.*)\. Vous pouvez', app_validation_message) if msg_first_part: -- GitLab