diff --git a/modules/societegenerale/backend.py b/modules/societegenerale/backend.py index d614e810..408c7b46 100644 --- a/modules/societegenerale/backend.py +++ b/modules/societegenerale/backend.py @@ -23,9 +23,10 @@ from __future__ import with_statement from weboob.capabilities.bank import ICapBank, AccountNotFound from weboob.tools.backend import BaseBackend, BackendConfig -from weboob.tools.value import ValueBackendPassword +from weboob.tools.value import Value, ValueBackendPassword from .browser import SocieteGenerale +from .sgpe.browser import SGEnterpriseBrowser, SGProfessionalBrowser __all__ = ['SocieteGeneraleBackend'] @@ -38,11 +39,15 @@ class SocieteGeneraleBackend(BaseBackend, ICapBank): VERSION = '0.g' LICENSE = 'AGPLv3+' DESCRIPTION = u'Société Générale French bank website' - CONFIG = BackendConfig(ValueBackendPassword('login', label='Account ID', masked=False), - ValueBackendPassword('password', label='Password')) - BROWSER = SocieteGenerale + CONFIG = BackendConfig( + ValueBackendPassword('login', label='Account ID', masked=False), + ValueBackendPassword('password', label='Password'), + Value('website', label='Website to use', default='par', + choices={'par': 'Particuliers', 'pro': 'Professionnels', 'ent': 'Entreprises'})) def create_default_browser(self): + b = {'par': SocieteGenerale, 'pro': SGProfessionalBrowser, 'ent': SGEnterpriseBrowser} + self.BROWSER = b[self.config['website'].get()] return self.create_browser(self.config['login'].get(), self.config['password'].get()) diff --git a/modules/societegenerale/sgpe/__init__.py b/modules/societegenerale/sgpe/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/modules/societegenerale/sgpe/browser.py b/modules/societegenerale/sgpe/browser.py new file mode 100644 index 00000000..8641784e --- /dev/null +++ b/modules/societegenerale/sgpe/browser.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Laurent Bachelier +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + + +from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword +from weboob.tools.ordereddict import OrderedDict + +from .pages import LoginPage, AccountsPage + + +__all__ = ['SGProfessionalBrowser', 'SGEnterpriseBrowser'] + + +class SGPEBrowser(BaseBrowser): + PROTOCOL = 'https' + ENCODING = None + + def __init__(self, *args, **kwargs): + self.PAGES = OrderedDict(( + ('%s://%s/Pgn/.+PageID=Compte&.+' % (self.PROTOCOL, self.DOMAIN), AccountsPage), + ('%s://%s/' % (self.PROTOCOL, self.DOMAIN), LoginPage), + )) + BaseBrowser.__init__(self, *args, **kwargs) + + def is_logged(self): + if not self.page or self.is_on_page(LoginPage): + return False + + error = self.page.get_error() + if error is None: + return True + + return False + + def login(self): + assert isinstance(self.username, basestring) + assert isinstance(self.password, basestring) + assert self.password.isdigit() + + if not self.is_on_page(LoginPage): + self.location('https://' + self.DOMAIN + '/', no_login=True) + + self.page.login(self.username, self.password) + + if self.is_on_page(LoginPage): + raise BrowserIncorrectPassword() + + +class SGProfessionalBrowser(SGPEBrowser): + DOMAIN = 'professionnels.secure.societegenerale.fr' + LOGIN_FORM = 'auth_reco' + + +class SGEnterpriseBrowser(SGPEBrowser): + DOMAIN = 'entreprises.secure.societegenerale.fr' + LOGIN_FORM = 'auth' diff --git a/modules/societegenerale/sgpe/pages.py b/modules/societegenerale/sgpe/pages.py new file mode 100644 index 00000000..bb577efb --- /dev/null +++ b/modules/societegenerale/sgpe/pages.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Laurent Bachelier +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + +from logging import error +import re +from weboob.tools.json import json + +from weboob.tools.mech import ClientForm + +from weboob.tools.browser import BasePage + +from ..captcha import Captcha, TileError + + +__all__ = ['LoginPage', 'AccountsPage'] + + +class SGPEPage(BasePage): + def get_error(self): + try: + return self.document.xpath('//div[@class="ngo_mire_reco_message"]')[0] \ + .text.strip() + return self.document.xpath('//*[@id="nge_zone_centre"]//[@class="nge_cadre_message_utilisateur"')[0] \ + .text_content.strip() + except IndexError: + return None + + +class LoginPage(SGPEPage): + def login(self, login, password): + DOMAIN = self.browser.DOMAIN + + url_login = 'https://' + DOMAIN + '/' + + base_url = 'https://' + DOMAIN + url = base_url + '//sec/vk/gen_crypto?estSession=0' + headers = {'Referer': url_login} + request = self.browser.request_class(url, None, headers) + infos_data = self.browser.readurl(request) + + infos_data = re.match('^_vkCallback\((.*)\);$', infos_data).group(1) + + infos = json.loads(infos_data.replace("'", '"')) + + url = base_url + '//sec/vk/gen_ui?modeClavier=0&cryptogramme=' + infos["crypto"] + + self.browser.readurl(url) + img = Captcha(self.browser.openurl(url), infos) + + try: + img.build_tiles() + except TileError, err: + error("Error: %s" % err) + if err.tile: + err.tile.display() + + self.browser.select_form(self.browser.LOGIN_FORM) + self.browser.controls.append(ClientForm.TextControl('text', 'codsec', {'value': ''})) + self.browser.controls.append(ClientForm.TextControl('text', 'cryptocvcs', {'value': ''})) + self.browser.controls.append(ClientForm.TextControl('text', 'vk_op', {'value': 'auth'})) + self.browser.set_all_readonly(False) + + #self.browser['codcli'] = login + self.browser['user_id'] = login + self.browser['codsec'] = img.get_codes(password[:6]) + self.browser['cryptocvcs'] = infos["crypto"] + self.browser.form.action = base_url + '/authent.html' + self.browser.submit(nologin=True) + + +class AccountsPage(SGPEPage): + pass