Newer
Older
# This file is part of a weboob module.
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with this weboob module. If not, see <http://www.gnu.org/licenses/>.
from io import BytesIO
from weboob.exceptions import BrowserUnavailable, BrowserIncorrectPassword, NoAccountsException, ActionNeeded
from weboob.browser.pages import LoggedPage
from weboob.browser.filters.standard import CleanText, Regexp
from weboob.tools.captcha.virtkeyboard import VirtKeyboard
class UnavailablePage(MyHTMLPage):
def on_load(self):
'0': ('daa52d75287bea58f505823ef6c8b96c', 'e5d6dc589f00e7ec3ba0e45a1fee1220'),
'1': ('f5da96c2592803a8cdc5a928a2e4a3b0', '9732b03ce3bdae7a44df9a7b4e092a07'),
'2': ('9ff78367d5cb89cacae475368a11e3af', '3b4387242c42bd39dbc263eac0718a49'),
'3': ('908a0a42a424b95d4d885ce91bc3d920', '14fa1e5083fa0a0c0cded72a2139921b'),
'4': ('3fc069f33b801b3d0cdce6655a65c0ac', '72792dbef888f1176f1974c86a94a084'),
'5': ('58a2afebf1551d45ccad79fad1600fc3', '1e9ddf1e5a12ebaeaea26cca6f752a87'),
'6': ('7fedfd9e57007f2985c3a1f44fb38ea1', '4e3a917198e89a2c16b9379f9a33f2a1'),
'7': ('389b8ef432ae996ac0141a2fcc7b540f', '33b90787a8014667b2acd5493e5641d2'),
'8': ('bf357ff09cc29ea544991642cd97d453', 'e4b30e90bbc2c26c2893120c8adc9d64'),
'9': ('b744015eb89c1b950e13a81364112cd6', 'b400c35438960de101233b9c846cd5eb'),
def __init__(self, page):
img_url = (
Regexp(CleanText('//style'), r'background:url\((.*?)\)', default=None)(page.doc)
or Regexp(CleanText('//script'), r'IMG_ALL = "(.*?)"', default=None)(page.doc)
)
img_url = page.doc.xpath('//img[@id="imageCVS"]')[0].attrib['src']
for i, _ in enumerate(page.doc.xpath('//div[@id="imageclavier"]//button')):
coords[code] = (x + 4, y + 4, x + width - 8, y + height - 8)
data = page.browser.open(img_url).content
VirtKeyboard.__init__(self, BytesIO(data), coords, self.color)
self.check_symbols(self.symbols, page.browser.responses_dirname)
def get_symbol_code(self, md5sum):
code = VirtKeyboard.get_symbol_code(self, md5sum)
return '%02d' % int(code.split('_')[-1])
code = ''
for c in string:
code += self.get_symbol_code(self.symbols[c])
return code
return VirtKeyboard.get_symbol_coords(self, (x1 + 3, y1 + 3, x2 - 3, y2 - 3))
form = self.get_form(name='formAccesCompte')
form['password'] = vk.get_string_code(pwd)
form['username'] = login
class repositionnerCheminCourant(LoggedPage, MyHTMLPage):
def on_load(self):
super(repositionnerCheminCourant, self).on_load()
response = self.browser.open("https://voscomptesenligne.labanquepostale.fr/voscomptes/canalXHTML/securite/authentification/initialiser-identif.ea")
if isinstance(response.page, Initident):
response.page.on_load()
if "vous ne disposez pas" in response.text:
raise BrowserIncorrectPassword("No online banking service for these ids")
if 'Nous vous invitons à renouveler votre opération ultérieurement' in response.text:
raise BrowserUnavailable()
class PersonalLoanRoutagePage(LoggedPage, MyHTMLPage):
def form_submit(self):
form = self.get_form()
form.submit()
class Initident(LoggedPage, MyHTMLPage):
def on_load(self):
self.browser.open("https://voscomptesenligne.labanquepostale.fr/voscomptes/canalXHTML/securite/authentification/verifierMotDePasse-identif.ea")
if self.doc.xpath("""//span[contains(text(), "L'identifiant utilisé est celui d'une Entreprise ou d'une Association")]"""):
raise BrowserIncorrectPassword("L'identifiant utilisé est celui d'une Entreprise ou d'une Association")
no_accounts = CleanText('//div[@class="textFCK"]')(self.doc)
if no_accounts:
raise NoAccountsException(no_accounts)
MyHTMLPage.on_load(self)
class CheckPassword(LoggedPage, MyHTMLPage):
def on_load(self):
self.browser.location("https://voscomptesenligne.labanquepostale.fr/voscomptes/canalXHTML/comptesCommun/synthese_assurancesEtComptes/init-synthese.ea")
class AccountDesactivate(LoggedPage, MyHTMLPage):
class TwoFAPage(MyHTMLPage):
def on_load(self):
# For pro browser this page can provoke a disconnection
# We have to do login again without 2fa
deconnexion = self.doc.xpath('//iframe[contains(@id, "deconnexion")] | //p[@class="txt" and contains(text(), "Session expir")]')
if deconnexion:
self.browser.login_without_2fa()
def get_auth_method(self):
status_message = CleanText('//div[@class="textFCK"]')(self.doc)
if re.search(
'Une authentification forte via Certicode Plus vous'
+ '|vous rendre sur l’application mobile La Banque Postale',
status_message
):
elif re.search(
'authentification forte via Certicode vous'
+ '|code de sécurité que vous recevrez par SMS',
status_message
):
elif re.search(
'avez pas de solution d’authentification forte'
+ "|avez pas encore activé votre service gratuit d'authentification forte",
status_message
):
elif (
'Nous rencontrons un problème pour valider votre opération. Veuillez reessayer plus tard'
in status_message
):
raise BrowserUnavailable(status_message)
elif (
'votre Espace Client Internet requiert une authentification forte tous les 90 jours'
in status_message
):
# Only first sentence explains 'why', the rest is 'how'
short_message = CleanText('(//div[@class="textFCK"])[1]//p[1]')(self.doc)
url = self.get_skip_url()
if not url:
raise ActionNeeded(
"Une authentification forte est requise sur votre espace client : %s" % short_message
)
else:
# raise an error to avoid silencing other no2fa cases
raise AssertionError("No 2FA case to skip, or new 2FA case to trigger")
raise AssertionError('Unhandled login message: "%s"' % status_message)
def get_skip_url(self):
return Link('//div[@class="certicode_footer"]/a')(self.doc)
class Validated2FAPage(MyHTMLPage):
pass
class SmsPage(MyHTMLPage):
def check_if_is_blocked(self):
error_message = CleanText('//div[@class="textFCK"]')(self.doc)
if "l'accès à votre Espace client est bloqué" in error_message:
raise ActionNeeded(error_message)
def get_sms_form(self):
return self.get_form()
def is_sms_wrong(self):
return (
'Le code de sécurité que vous avez saisi est erroné'
in CleanText('//div[@id="DSP2_Certicode_AF_ErreurCode1"]//div[@class="textFCK"]')(self.doc)
)
class DecoupledPage(MyHTMLPage):
def get_decoupled_message(self):
return CleanText('//div[@class="textFCK"]/p[contains(text(), "Validez votre authentification")]')(self.doc)