Commit a83edc78 authored by Benjamin Bouvier's avatar Benjamin Bouvier Committed by Romain Bignon

[creditmutuel] Implement OTP validation.

This is very basic, as it implements all the logic in
MobileConfirmationPage, which is not ideal. This lets 2 minutes to the
user so they have an opportunity to validate their OTP code, after which
it raises the AppValidation exception instead.
parent 5d4a84af
......@@ -21,6 +21,7 @@ from __future__ import unicode_literals
import re
import hashlib
import time
from decimal import Decimal, InvalidOperation
from dateutil.relativedelta import relativedelta
......@@ -106,6 +107,19 @@ class FiscalityConfirmationPage(LoggedPage, HTMLPage):
class MobileConfirmationPage(LoggedPage, HTMLPage):
# OTP process:
# - first we get on this page, and the mobile app is pinged: scrap some JS
# object information from the HTML's page, to reuse later, including the
# page's URL to get a status update about OTP validation.
# - ping the status update page every second, as does the website. It
# returns a weird XML object, with a status field containing PENDING or
# - once the status update page returns VALIDATED, do another POST request
# to finalize validation, using state recorded in the first step
# (otp_hidden).
MAX_WAIT = 120 # in seconds
# We land on this page for some connections, but can still bypass this verification for now
def on_load(self):
link = Attr('//a[contains(text(), "Accéder à mon Espace Client sans Confirmation Mobile")]', 'href', default=None)(self.doc)
......@@ -117,7 +131,50 @@ class MobileConfirmationPage(LoggedPage, HTMLPage):
msg = CleanText('//div[@id="inMobileAppMessage"]')(self.doc)
if msg:
display_msg ='Confirmer votre connexion depuis votre appareil ".+"', msg).group()
script = CleanText('//script[contains(text(), "otpInMobileAppParameters")]')(self.doc)
transaction_id ="transactionId: '(\w+)'", script)
if transaction_id is None:
raise Exception('missing transaction_id in Credit Mutuel OTP')
transaction_id =
validation_status_url ="getTransactionValidationStateUrl: '(.*)', pollingInterval:", script)
if validation_status_url is None:
raise Exception('missing validation_status_url in Credit Mutuel OTP')
validation_status_url =
otp_hidden = CleanText('//input[@name="otp_hidden"]/@value')(self.doc)
if otp_hidden is None:
raise Exception('missing otp_hidden in Credit Mutuel OTP')
num_attempts = 0
while num_attempts < self.MAX_WAIT:
num_attempts += 1
response =, method='POST', data={"transactionId":transaction_id})
if response.status_code == 200:
if 'PENDING' not in response.text:
response =
"otp_hidden": otp_hidden,
"global_backup_hidden_key": "",
"_FID_DoValidate.x": "0",
"_FID_DoValidate.y": "0",
if response.status_code != 200:
raise AppValidation(display_msg)
assert False, "Mobile authentication method not handled"
class EmptyPage(LoggedPage, HTMLPage):
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment