From f813a62653cc846720347e53eed7dde981e7698b Mon Sep 17 00:00:00 2001 From: Romain Bignon Date: Sat, 20 Oct 2018 13:21:30 +0200 Subject: [PATCH] bnporc: support triple rotations of password --- modules/bnporc/pp/browser.py | 19 ++++++++++++- modules/bnporc/pp/pages.py | 52 +++++++++++++++++------------------- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/modules/bnporc/pp/browser.py b/modules/bnporc/pp/browser.py index d7cea9b7a4..845589347c 100644 --- a/modules/bnporc/pp/browser.py +++ b/modules/bnporc/pp/browser.py @@ -40,7 +40,7 @@ LoginPage, AccountsPage, AccountsIBANPage, HistoryPage, TransferInitPage, ConnectionThresholdPage, LifeInsurancesPage, LifeInsurancesHistoryPage, LifeInsurancesDetailPage, NatioVieProPage, CapitalisationPage, - MarketListPage, MarketPage, MarketHistoryPage, MarketSynPage, + MarketListPage, MarketPage, MarketHistoryPage, MarketSynPage, BNPKeyboard, RecipientsPage, ValidateTransferPage, RegisterTransferPage, AdvisorPage, AddRecipPage, ActivateRecipPage, ProfilePage, ListDetailCardPage, ListErrorPage, ) @@ -131,6 +131,23 @@ def do_login(self): if self.login.is_here(): self.page.login(self.username, self.password) + def change_pass(self, oldpass, newpass): + res = self.open('/identification-wspl-pres/grille?accessible=false') + url = '/identification-wspl-pres/grille/%s' % res.json()['data']['idGrille'] + keyboard = self.open(url) + vk = BNPKeyboard(self, keyboard) + data = {} + data['codeAppli'] = 'PORTAIL' + data['idGrille'] = res.json()['data']['idGrille'] + data['typeGrille'] = res.json()['data']['typeGrille'] + data['confirmNouveauPassword'] = vk.get_string_code(newpass) + data['nouveauPassword'] = vk.get_string_code(newpass) + data['passwordActuel'] = vk.get_string_code(oldpass) + response = self.location('/mcs-wspl/rpc/modifiercodesecret', data=data) + if response.json().get('messageIden').lower() == 'nouveau mot de passe invalide': + return False + return True + @need_login def get_profile(self): self.profile.go(data=JSON({})) diff --git a/modules/bnporc/pp/pages.py b/modules/bnporc/pp/pages.py index b140dc38f9..1e2f099222 100644 --- a/modules/bnporc/pp/pages.py +++ b/modules/bnporc/pp/pages.py @@ -49,23 +49,6 @@ class ConnectionThresholdPage(HTMLPage): - def change_pass(self, oldpass, newpass): - res = self.browser.open('/identification-wspl-pres/grille?accessible=false') - url = '/identification-wspl-pres/grille/%s' % res.json()['data']['idGrille'] - keyboard = self.browser.open(url) - vk = BNPKeyboard(self, keyboard) - data = {} - data['codeAppli'] = 'PORTAIL' - data['idGrille'] = res.json()['data']['idGrille'] - data['typeGrille'] = res.json()['data']['typeGrille'] - data['confirmNouveauPassword'] = vk.get_string_code(newpass) - data['nouveauPassword'] = vk.get_string_code(newpass) - data['passwordActuel'] = vk.get_string_code(oldpass) - response = self.browser.location('/mcs-wspl/rpc/modifiercodesecret', data=data) - if response.json().get('messageIden').lower() == 'nouveau mot de passe invalide': - return False - return True - def make_date(self, yy, m, d): current = datetime.now().year if yy > current - 2000: @@ -114,21 +97,34 @@ def looks_legit(self, password): def on_load(self): msg = CleanText('//div[@class="confirmation"]//span[span]')(self.doc) - raise BrowserPasswordExpired(msg) + self.logger.warning('Password expired.') if not self.looks_legit(self.browser.password): # we may not be able to restore the password, so reject it + self.logger.warning('Unable to restore it, it is not legit.') raise BrowserPasswordExpired(msg) - new_pass = ''.join([str((int(l) + 1) % 10) for l in self.browser.password]) - self.logger.warning('Password expired. Renewing it. Temporary password is %s', new_pass) - if not self.change_pass(self.browser.password, new_pass): - self.logger.warning('New temp password is rejected, giving up') - raise BrowserPasswordExpired() - - if not self.change_pass(new_pass, self.browser.password): + new_passwords = [] + for i in range(3): + new_pass = ''.join([str((int(l) + i + 1) % 10) for l in self.browser.password]) + if not self.looks_legit(new_pass): + self.logger.warning('%s is not legit', new_pass) + raise BrowserPasswordExpired(msg) + new_passwords.append(new_pass) + + current_password = self.browser.password + for new_pass in new_passwords: + self.logger.warning('Renewing with temp password is %s', new_pass) + if not self.browser.change_pass(current_password, new_pass): + self.logger.warning('New temp password is rejected, giving up') + raise BrowserPasswordExpired(msg) + current_password = new_pass + + if not self.browser.change_pass(current_password, self.browser.password): self.logger.error('Could not restore old password!') + self.logger.warning('Old password restored.') + def cast(x, typ, default=None): try: @@ -151,11 +147,11 @@ class BNPKeyboard(GridVirtKeyboard): '8': 'c60b723b3d95a46416b34c2cbefba3ed', '9': 'a13b8c3617a7bf854590833ddfb97f1f'} - def __init__(self, page, image): + def __init__(self, browser, image): symbols = list('%02d' % x for x in range(1, 11)) super(BNPKeyboard, self).__init__(symbols, 5, 2, BytesIO(image.content), self.color, convert='RGB') - self.check_symbols(self.symbols, page.browser.responses_dirname) + self.check_symbols(self.symbols, browser.responses_dirname) class ListErrorPage(JsonPage): @@ -214,7 +210,7 @@ def on_load(self): def login(self, username, password): url = '/identification-wspl-pres/grille/%s' % self.get('data.grille.idGrille') keyboard = self.browser.open(url) - vk = BNPKeyboard(self, keyboard) + vk = BNPKeyboard(self.browser, keyboard) target = self.browser.BASEURL + 'SEEA-pa01/devServer/seeaserver' user_agent = self.browser.session.headers.get('User-Agent') or '' -- GitLab